本文說明如何將 Windows Forms 剪貼簿和拖放作業升級至 .NET 10 中新的類型安全 API。 您將學習如何使用Clipboard.TryGetData和Clipboard.SetDataAsJson<T>(String, T)這些新方法,理解哪些內建類型可在不變更的情況下運行,並在移除BinaryFormatter之後,探索處理自訂類型和舊版資料的策略。
BinaryFormatter 由於安全性弱點,已從 .NET 9 的執行階段中移除。 此變更導致自訂物件的剪貼板和拖放操作出現問題。 .NET 10 引進了新的 API,這些 API 使用 JSON 序列化和類型安全方法來還原此功能、提高安全性,並提供更好的錯誤處理和跨進程相容性。
Clipboard.SetData(String, Object) 不再適用於需要 BinaryFormatter 序列化的自訂類型。 這個方法會執行複製作業 (預設) ,立即序列化資料,但序列化現在會失敗,因為已移除所需的類型 BinaryFormatter 。
Clipboard.GetData(String) 在 .NET 10 中已過時。 當還原序列化需要但未啟用 BinaryFormatter 時,GetData() 會傳回 NotSupportedException 實例。 使用 new Clipboard.TryGetData 和 Clipboard.SetDataAsJson<T>(String, T) 方法進行自訂物件的類型安全作業和 JSON 序列化。
下列各節提供詳細的移轉指引、說明哪些類型無需變更即可運作,並示範如何處理新的開發和舊版資料案例。
先決條件
在繼續之前,請檢閱下列概念:
- 在 .NET 9 之前,應用程式如何在剪貼簿與拖放情境中使用
BinaryFormatter。 - 導致移除
BinaryFormatter的安全漏洞。 - 如何使用
System.Text.Json序列化模式及其限制。
如需詳細資訊,請參閱下列文章:
移除 BinaryFormatter 的重大變更
.NET 9 中移除 BinaryFormatter 徹底改變了 Windows Forms 處理剪貼板和具有自定義類型的拖放操作的方式。 這些變更會影響現有的程式碼模式,需要仔細遷移以維護功能。
自訂類型不再自動序列化
在 .NET 8 和更早版本中,您可以呼叫 SetData()將任何可序列化的自訂物件放在剪貼簿上。
BinaryFormatter自動處理序列化。 從 .NET 9 開始, SetData() 仍會執行立即序列化資料的複製作業,但此序列化對於需要 BinaryFormatter 的類型會失敗,因為它已被移除。
下列程式碼不再有效:
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void BrokenCustomTypeExample()
{
// This worked in .NET 8 and earlier but silently fails starting with .NET 9
Person person = new Person { Name = "John", Age = 30 };
Clipboard.SetData("MyApp.Person", person); // No data is stored
// Later attempts to retrieve the data return a NotSupportedException instance
object data = Clipboard.GetData("MyApp.Person");
}
<Serializable>
Public Class Person
Public Property Name As String
Public Property Age As Integer
End Class
Public Shared Sub BrokenCustomTypeExample()
' This worked in .NET 8 and earlier but silently fails starting with .NET 9
Dim person As New Person With {.Name = "John", .Age = 30}
Clipboard.SetData("MyApp.Person", person) ' No data is stored
' Later attempts to retrieve the data return a NotSupportedException instance
Dim data As Object = Clipboard.GetData("MyApp.Person")
End Sub
你可能會看到什麼
- 方法
SetData()可正常完成,而不會拋出例外狀況。 - 資料會放在剪貼簿上,但對於需要
BinaryFormatter的類型,序列化會失敗。 - 稍後嘗試擷取資料時,
GetData()會傳回一個指出BinaryFormatter是必要但尚未啟用的 NotSupportedException 實例。
移轉指引
使用新 SetDataAsJson<T>() 方法或手動序列化為 string 或 byte[]。 如需詳細資訊,請參閱使用 自訂類型 一節。
GetData() 已過時 - 改用 TryGetData<T>()
舊版 GetData() 方法在 .NET 10 中已過時。 在大部分情況下,這個方法會成功傳回資料,但若反序列化需要 BinaryFormatter 且尚未啟用,GetData() 會傳回一個 NotSupportedException 實例,指示需要 BinaryFormatter。 您應該移轉至新的類型安全 TryGetData<T>() 方法,以取得更好的錯誤處理和類型安全。
下列範例顯示您應該避免的過時模式:
public static void ObsoleteGetDataExample()
{
// Don't use - GetData() is obsolete in .NET 10
object data = Clipboard.GetData("MyApp.Person"); // Obsolete method
// Returns a NotSupportedException instance for a custom object type
if (data is Person person)
{
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}");
}
}
Public Shared Sub ObsoleteGetDataExample()
' Don't use - GetData() is obsolete in .NET 10
Dim data As Object = Clipboard.GetData("MyApp.Person") ' Obsolete method
' Returns a NotSupportedException instance for a custom object type
If TypeOf data Is Person Then
Dim person As Person = DirectCast(data, Person)
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}")
End If
End Sub
相反地,請使用現代類型安全方法:TryGetData<T>()
public static void ModernTryGetDataExample()
{
var data = new Person { Name = "Alice", Age = 28 };
Clipboard.SetDataAsJson("MyAppData", data);
// Use this - type-safe approach with TryGetData<T>()
if (Clipboard.TryGetData("MyApp.Person", out Person person))
{
// person is guaranteed to be the correct type
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}");
}
else
{
// Handle the case where data isn't available or is the wrong type
MessageBox.Show("Unable to retrieve person data from clipboard");
}
}
Public Shared Sub ModernTryGetDataExample()
Dim data As New Person With {.Name = "Alice", .Age = 30}
Clipboard.SetDataAsJson("MyAppData", data)
' Use this - type-safe approach with TryGetData(Of T)()
Dim person As Person = Nothing
If Clipboard.TryGetData("MyApp.Person", person) Then
' person is guaranteed to be the correct type
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}")
Else
' Handle the case where data isn't available or is the wrong type
MessageBox.Show("Unable to retrieve person data from clipboard")
End If
End Sub
TryGetData<T>() 的優點
- 類型安全:無需轉換——該方法返回您請求的確切類型。
- 清除錯誤處理:傳回布林成功指標,而不是使用空值或例外模式。
- 面向未來設計:旨在與新的序列化方法和支持遺留數據的技術配合使用。
如何識別受影響的程式碼
尋找:
- 任何
GetData()呼叫,因為無論資料類型如何,整個方法都會過時。 -
DataObject.GetData()和IDataObject.GetData()在拖放操作中的使用。
移轉指引
將所有 GetData() 用法替換為類型安全的 TryGetData<T>() 方法。 如需所有多載的完整範例,請參閱 新的類型安全 API 一節。
新的類型安全 API 介面
.NET 10 引進了三個新的 API 系列,可提供類型安全、更好的錯誤處理,以及剪貼簿和拖放作業的 JSON 序列化支援:
- TryGetData 檢索資料的方法
- SetDataAsJson<T>(String, T) 儲存資料的方法
- ITypedDataObject 拖放操作的界面
TryGetData<T>() 方法
TryGetData<T>() 系列取代了過時的 GetData() 方法。 它為您的剪貼簿操作提供類型安全的檢索和清晰的成功或失敗指示。
基本類型安全擷取
public static void BasicTypeSafeRetrievalExamples()
{
// Retrieve text data using a standard format
if (Clipboard.TryGetData(DataFormats.Text, out string textData))
Console.WriteLine($"Text: {textData}");
// Retrieve an integer using a custom format
if (Clipboard.TryGetData("NumberData", out int numberData))
Console.WriteLine($"Number: {numberData}");
// Retrieve Unicode text using a standard format
if (Clipboard.TryGetData(DataFormats.UnicodeText, out string unicodeText))
Console.WriteLine($"Unicode: {unicodeText}");
// Retrieve raw text data with OLE conversion control
if (Clipboard.TryGetData(DataFormats.Text, out string rawText))
Console.WriteLine($"Raw: {rawText}");
// Retrieve file drops using a standard format
if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files))
Console.WriteLine($"Files: {string.Join(", ", files)}");
}
Public Shared Sub BasicTypeSafeRetrievalExamples()
' Retrieve text data using a standard format
Dim textData As String = Nothing
If Clipboard.TryGetData(DataFormats.Text, textData) Then
Console.WriteLine($"Text: {textData}")
End If
' Retrieve an integer using a custom format
Dim numberData As Integer
If Clipboard.TryGetData("NumberData", numberData) Then
Console.WriteLine($"Number: {numberData}")
End If
' Retrieve Unicode text using a standard format
Dim unicodeText As String = Nothing
If Clipboard.TryGetData(DataFormats.UnicodeText, unicodeText) Then
Console.WriteLine($"Unicode: {unicodeText}")
End If
' Retrieve raw text data with OLE conversion control
Dim rawText As String = Nothing
If Clipboard.TryGetData(DataFormats.Text, rawText) Then
Console.WriteLine($"Raw: {rawText}")
End If
' Retrieve file drops using a standard format
Dim files As String() = Nothing
If Clipboard.TryGetData(DataFormats.FileDrop, files) Then
Console.WriteLine($"Files: {String.Join(", ", files)}")
End If
End Sub
自訂 JSON 類型
public static void CustomJsonTypesExamples()
{
// Retrieve a custom type stored with SetDataAsJson<T>()
if (Clipboard.TryGetData("Person", out Person person))
Console.WriteLine($"Person: {person.Name}");
// Retrieve application-specific data formats
if (Clipboard.TryGetData("MyApp.Settings", out AppSettings settings))
Console.WriteLine($"Settings: {settings.Theme}");
// Retrieve complex custom objects
if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc))
Console.WriteLine($"Document: {doc.Title}");
}
Public Shared Sub CustomJsonTypesExamples()
' Retrieve a custom type stored with SetDataAsJson(Of T)()
Dim person As Person = Nothing
If Clipboard.TryGetData("Person", person) Then
Console.WriteLine($"Person: {person.Name}")
End If
' Retrieve application-specific data formats
Dim settings As AppSettings = Nothing
If Clipboard.TryGetData("MyApp.Settings", settings) Then
Console.WriteLine($"Settings: {settings.Theme}")
End If
' Retrieve complex custom objects
Dim doc As DocumentInfo = Nothing
If Clipboard.TryGetData("DocumentData", doc) Then
Console.WriteLine($"Document: {doc.Title}")
End If
End Sub
SetDataAsJson<T>() 方法
這些方法使用 System.Text.Json 進行自動 JSON 序列化,並進行類型安全儲存。
指定自訂格式
public static void CustomFormatExample()
{
var settings = new AppSettings { Theme = "Dark", AutoSave = true };
// Use a custom format for better organization
Clipboard.SetDataAsJson("MyApp.Settings", settings);
}
Public Shared Sub CustomFormatExample()
Dim settings As New AppSettings With {.Theme = "Dark", .AutoSave = True}
' Use a custom format for better organization
Clipboard.SetDataAsJson("MyApp.Settings", settings)
End Sub
自動格式推斷
透過指定類型名稱作為資料格式, TryGetData<T> 可以自動推斷格式:
public static void AutomaticFormatInferenceExample()
{
var person = new Person { Name = "Alice", Age = 25 };
// Use the type name as the format
Clipboard.SetDataAsJson(typeof(Person).FullName, person);
// Retrieve the data and infer the format automatically
if (Clipboard.TryGetData(out Person retrievedPerson))
{
Console.WriteLine($"Retrieved: {retrievedPerson.Name}");
}
}
Public Shared Sub AutomaticFormatInferenceExample()
Dim person As New Person With {.Name = "Alice", .Age = 25}
' Use the type name as the format
Clipboard.SetDataAsJson(GetType(Person).FullName, person)
' Retrieve the data and infer the format automatically
Dim retrievedPerson As Person = Nothing
If Clipboard.TryGetData(retrievedPerson) Then
Console.WriteLine($"Retrieved: {retrievedPerson.Name}")
End If
End Sub
ITypedDataObject 介面
ITypedDataObject 接口通過擴展 IDataObject 並使用類型化方法,來實現類型安全的拖放操作。
從 .NET 10 開始,DataObject(在拖放案例中的常見類型)會實作ITypedDataObject。
在拖放案例中使用 ITypedDataObject
private void OnDragDrop(object sender, DragEventArgs e)
{
if (e.Data is ITypedDataObject typedData)
{
// Retrieve files from drag data using a standard format
if (typedData.TryGetData(DataFormats.FileDrop, out string[] files))
Console.WriteLine($"Dropped files: {string.Join(", ", files)}");
// Retrieve text using a standard format
if (typedData.TryGetData(DataFormats.Text, out string text))
Console.WriteLine($"Dropped text: {text}");
// Retrieve custom items using an application-specific format
if (typedData.TryGetData("CustomItem", out MyItem item))
Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}");
}
}
Private Sub OnDragDrop(sender As Object, e As DragEventArgs)
If TypeOf e.Data Is ITypedDataObject Then
Dim typedData As ITypedDataObject = CType(e.Data, ITypedDataObject)
' Retrieve files from drag data using a standard format
Dim files As String() = Nothing
If typedData.TryGetData(DataFormats.FileDrop, files) Then
Console.WriteLine($"Dropped files: {String.Join(", ", files)}")
End If
' Retrieve text using a standard format
Dim text As String = Nothing
If typedData.TryGetData(DataFormats.Text, text) Then
Console.WriteLine($"Dropped text: {text}")
End If
' Retrieve custom items using an application-specific format
Dim item As MyItem = Nothing
If typedData.TryGetData("CustomItem", item) Then
Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}")
End If
End If
End Sub
不需要 JSON 序列化的類型
許多內建的 .NET 類型可與剪貼簿作業搭配使用,而不需要 JSON 序列化或 BinaryFormatter 支援。 這些類型會自動序列化為 .NET 遠端二進位格式 (NRBF),以提供有效率的儲存並維護類型安全。
這些類型使用 NRBF,與舊版 BinaryFormatter使用的高效二進位格式相同。 NRBF 序列化提供下列主要優點:
- 緊湊的二進位表示:實現高效的儲存和傳輸。
- 內建類型資訊:在來回作業期間保留確切的 .NET 類型。
- 跨進程相容性:在不同的 .NET 應用程式之間運作。
- 自動序列化:類型無需自訂程式碼即可序列化。
備註
執行立即序列化資料的複製操作等 SetData() 方法,確保剪貼簿資料即使在目前進程退出後仍保留。 如果您直接將類型與 DataObject 一起使用 SetDataObject(dataObject, copy),則可以控制序列化何時發生。 將參數設為 copy (預設值) 會true強制立即序列化,而false延遲序列化直到需要為止。 設定 copy 為 false ,且資料會在相同的進程中擷取,則可能不需要序列化,但在進程結束之後,資料不會持續存在。
如需技術詳細資料,請參閱 .NET 遠端二進位格式規格。
支援 NRBF 編碼資料的類別會在命名空間中 System.Formats.Nrbf 實作。
類型安全保證
Windows Forms 為這些內建類型提供數個安全機制:
- 精確類型比對。 TryGetData 僅傳回要求的類型。
- 自動驗證。 Windows Forms 會在還原序列化期間驗證類型相容性。
- 沒有任意程式碼執行。 與使用 BinaryFormatter 的自訂類型不同,這些類型無法執行惡意程式碼。
- 需要內容驗證。 您仍然必須驗證應用程式邏輯的資料內容和範圍。
- 沒有尺寸限制。 大型陣列或點陣圖不會自動受到限制。 監控記憶體使用量。
支援的基本類型
下列基本類型可與剪貼簿和 DataObject 作業無縫搭配使用。 您不需要自訂序列化或設定。 剪貼簿系統會自動處理這些內建的 .NET 類型:
-
bool、byte、char、decimal、double、short、int和long。 -
sbyte、ushort、uint、ulong、float和string。 -
TimeSpan與DateTime。
下列範例顯示這些基本類型如何直接使用 SetData() 和 TryGetData<T>() 方法:
public static void PrimitiveTypesExample()
{
// Numeric types
Clipboard.SetData("MyInt", 42);
Clipboard.SetData("MyDouble", 3.14159);
Clipboard.SetData("MyDecimal", 123.45m);
// Text and character types
Clipboard.SetData("MyString", "Hello World");
Clipboard.SetData("MyChar", 'A');
// Boolean and date/time types
Clipboard.SetData("MyBool", true);
Clipboard.SetData("MyDateTime", DateTime.Now);
Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30));
// Later retrieval with type safety
if (Clipboard.TryGetData("MyTimeSpan", out TimeSpan value))
{
Console.WriteLine($"Clipboard value is: {value}");
}
}
Public Shared Sub PrimitiveTypesExample()
' Numeric types
Clipboard.SetData("MyInt", 42)
Clipboard.SetData("MyDouble", 3.14159)
Clipboard.SetData("MyDecimal", 123.45D)
' Text and character types
Clipboard.SetData("MyString", "Hello World")
Clipboard.SetData("MyChar", "A"c)
' Boolean and date/time types
Clipboard.SetData("MyBool", True)
Clipboard.SetData("MyDateTime", DateTime.Now)
Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30))
' Later retrieval with type safety
Dim value As TimeSpan
If Clipboard.TryGetData("MyTimeSpan", value) Then
Console.WriteLine($"Clipboard value is: {value}")
End If
End Sub
基本類型集合
支援的基本類型陣列和泛型清單無需額外配置即可運作。 但是,請記住以下限制:
- 所有陣列和清單元素都必須是支援的基本類型。
- 避免
string[]和List<string>,因為 NRBF 格式在處理字串集合中的 Null 值時具有複雜性。 - 個別儲存字串,或針對字串集合使用 JSON 序列化。
下列範例顯示如何在剪貼簿上設定陣列和清單:
public static void CollectionsExample()
{
// Arrays of primitive types
int[] numbers = { 1, 2, 3, 4, 5 };
Clipboard.SetData("NumberArray", numbers);
double[] coordinates = { 1.0, 2.5, 3.7 };
Clipboard.SetData("Coordinates", coordinates);
// Generic lists
List<int> intList = new List<int> { 10, 20, 30 };
Clipboard.SetData("IntList", intList);
// Retrieval maintains type safety
if (Clipboard.TryGetData("NumberArray", out int[] retrievedNumbers))
{
Console.WriteLine($"Numbers: {string.Join(", ", retrievedNumbers)}");
}
}
Public Shared Sub CollectionsExample()
' Arrays of primitive types
Dim numbers As Integer() = {1, 2, 3, 4, 5}
Clipboard.SetData("NumberArray", numbers)
Dim coordinates As Double() = {1.0, 2.5, 3.7}
Clipboard.SetData("Coordinates", coordinates)
' Generic lists
Dim intList As New List(Of Integer) From {10, 20, 30}
Clipboard.SetData("IntList", intList)
' Retrieval maintains type safety
Dim retrievedNumbers As Integer() = Nothing
If Clipboard.TryGetData("NumberArray", retrievedNumbers) Then
Console.WriteLine($"Numbers: {String.Join(", ", retrievedNumbers)}")
End If
End Sub
System.圖面類型
命名空間中的 System.Drawing 常見圖形類型可與剪貼簿和 DataObject 作業順暢地運作。 這些類型對於使用視覺元素且需要在元件或應用程式之間傳輸圖面相關資料的應用程式非常有用。 請注意,序列化 a Bitmap 可能會耗用大量記憶體,尤其是大型影像。 支援下列類型:
-
Point、、PointFRectangle、RectangleF。 -
Size、SizeF、Color。 -
Bitmap(序列化時可能會消耗大量記憶體)。
下列範例示範如何將這些圖形類型與剪貼簿作業搭配使用:
public static void SystemDrawingTypesExample()
{
// Geometric types
Point location = new Point(100, 200);
Rectangle bounds = new Rectangle(0, 0, 500, 300);
Size dimensions = new Size(800, 600);
Clipboard.SetData("Location", location);
Clipboard.SetData("Bounds", bounds);
Clipboard.SetData("Size", dimensions);
// Color information
Color backgroundColor = Color.FromArgb(255, 128, 64, 192);
Clipboard.SetData("BackColor", backgroundColor);
// Bitmap data (use with caution for large images)
Bitmap smallIcon = new Bitmap(16, 16);
Clipboard.SetData("Icon", smallIcon);
}
Public Shared Sub SystemDrawingTypesExample()
' Geometric types
Dim location As New Point(100, 200)
Dim bounds As New Rectangle(0, 0, 500, 300)
Dim dimensions As New Size(800, 600)
Clipboard.SetData("Location", location)
Clipboard.SetData("Bounds", bounds)
Clipboard.SetData("Size", dimensions)
' Color information
Dim backgroundColor As Color = Color.FromArgb(255, 128, 64, 192)
Clipboard.SetData("BackColor", backgroundColor)
' Bitmap data (use with caution for large images)
Dim smallIcon As New Bitmap(16, 16)
Clipboard.SetData("Icon", smallIcon)
End Sub
使用自訂類型
當您使用 SetDataAsJson<T>(String, T) 和 TryGetData 搭配自訂類型時, System.Text.Json 會自動處理序列化。 許多類型無需任何特殊配置即可運作,記錄、簡單類別和具有公用屬性的結構可以無縫序列化。
無需屬性即可運作的簡單類型
大多數簡單的自訂類型不需要特殊設定:
// Records work without any attributes.
public record PersonInfo(string Name, int Age, string Email);
// Simple classes serialize all public properties automatically.
public class DocumentMetadata
{
public string Title { get; set; }
public DateTime Created { get; set; }
public string Author { get; set; }
}
// Structs with public properties work seamlessly.
public struct Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
' Simple classes serialize all public properties automatically.
Public Class DocumentMetadata
Public Property Title As String
Public Property Created As DateTime
Public Property Author As String
End Class
' Structs with public properties work seamlessly.
Public Structure Point3D
Public Property X As Double
Public Property Y As Double
Public Property Z As Double
End Structure
使用 JSON 屬性進行進階控制
只有在您需要自訂序列化行為時,才使用 System.Text.Json 屬性。 如需序列化、屬性和進階設定選項的完整 System.Text.Json 指引,請參閱 .NET 中的 JSON 序列化和還原序列化。
下列範例顯示如何使用 JSON 屬性來控制序列化:
public class ClipboardFriendlyType
{
// Include a field that normally isn't serialized
[JsonInclude]
private int _privateData;
// Public properties are always serialized
public string Name { get; set; }
// Exclude sensitive or non-essential data
[JsonIgnore]
public string InternalId { get; set; }
// Handle property name differences for compatibility
[JsonPropertyName("display_text")]
public string DisplayText { get; set; }
// Control null value handling
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string OptionalField { get; set; }
}
Public Class ClipboardFriendlyType
' Include a field that normally isn't serialized
<JsonInclude>
Private _privateData As Integer
' Public properties are always serialized
Public Property Name As String
' Exclude sensitive or non-essential data
<JsonIgnore>
Public Property InternalId As String
' Handle property name differences for compatibility
<JsonPropertyName("display_text")>
Public Property DisplayText As String
' Control null value handling
<JsonIgnore(Condition:=JsonIgnoreCondition.WhenWritingNull)>
Public Property OptionalField As String
End Class
範例:具有自訂類型的剪貼簿作業
public static void CustomTypesClipboardOperationsExample()
{
var data = new ClipboardFriendlyType
{
Name = "Sample",
DisplayText = "Sample Display Text",
InternalId = "internal-123" // This property isn't serialized due to [JsonIgnore]
};
Clipboard.SetDataAsJson("MyAppData", data);
if (Clipboard.TryGetData("MyAppData", out ClipboardFriendlyType retrieved))
{
Console.WriteLine($"Retrieved: {retrieved.Name}");
// retrieved.InternalId is null because of [JsonIgnore]
}
}
Public Shared Sub CustomTypesClipboardOperationsExample()
Dim data As New ClipboardFriendlyType With {
.Name = "Sample",
.DisplayText = "Sample Display Text",
.InternalId = "internal-123" ' This property isn't serialized due to <JsonIgnore>
}
Clipboard.SetDataAsJson("MyAppData", data)
Dim retrieved As ClipboardFriendlyType = Nothing
If Clipboard.TryGetData("MyAppData", retrieved) Then
Console.WriteLine($"Retrieved: {retrieved.Name}")
' retrieved.InternalId is null because of <JsonIgnore>
End If
End Sub
啟用 BinaryFormatter 支援 (不建議)
謹慎
BinaryFormatter
不建議提供支援。 僅將其用作無法立即遷移到新類型安全 API 的舊版應用程式的臨時遷移橋接器。
如果您必須繼續在 .NET 10 中使用 BinaryFormatter 進行剪貼簿作業,請透過明確設定啟用有限的支援。 這種方法存在重大的安全風險,需要幾個步驟。
如需完整的逐步指示,請參閱啟用 BinaryFormatter 剪貼簿支援(不建議)。 如需一般移轉指引,請參閱 BinaryFormatter 移轉指南。
安全警告和風險
BinaryFormatter 本質上不安全,並且由於以下原因而被棄用:
- 任意程式碼執行漏洞:攻擊者可以在反序列化過程中執行惡意程式碼,使您的應用程式遭受遠端攻擊。
- 拒絕服務攻擊:惡意剪貼簿資料可能會消耗過多的記憶體或CPU資源,導致崩潰或不穩定。
- 資訊洩漏風險:攻擊者可能會從記憶體中提取敏感資料。
- 沒有安全界限:格式從根本上來說是不安全的,組態設定無法保護它。
只有在您更新應用程式以使用新的類型安全 API 時,才啟用此支援作為暫時橋接器。
如需詳細的安全性指導方針和設定步驟,請參閱操作指南中的 安全性警告和風險 。
實作以安全性為中心的類型解析程式
即使 BinaryFormatter 已啟用,您也必須實作類型解析程式,以將還原序列化限制為明確核准的類型。 請遵循下列指導方針:
- 使用明確的允許清單。 拒絕任何未明確核准的類型。
- 驗證類型名稱。 確保類型名稱完全符合預期值。
- 僅限於必要類型。 僅包含剪貼簿功能所需的類型。
- 拋出未知類型的例外。 明確拒絕未經授權的類型。
- 定期檢閱。 視需要稽核並更新允許清單。
如需完整的實作範例和程式碼範例,請參閱操作指南中的 實作以安全性為中心的類型解析程式 。
使用 AI 遷移剪貼簿程式碼
將剪貼簿作業從 .NET 8 移轉至 .NET 10 牽涉到跨多個檔案和類別的系統化程式碼變更。 GitHub Copilot 等 AI 工具可以透過識別舊版模式、建議現代取代和建立測試案例來協助加速您的移轉。 您可以使用 AI 來處理重複性任務,同時專注於驗證結果和處理邊緣情況,而不是手動搜尋程式碼庫並單獨轉換每個剪貼簿操作。
以下部分展示了剪貼簿遷移不同方面的具體提示策略,從尋找有問題的程式碼模式到建立強大的 JSON 可序列化類型和全面的測試套件。
使用 AI 識別舊版剪貼簿模式
使用 Copilot 掃描您的程式碼庫並找出需要移轉的剪貼簿作業。 這可協助您在開始實際移轉工作之前,瞭解所需的變更範圍。
Find all clipboard operations in my codebase that use GetData(), SetData() with custom objects, DataObject.GetData(), or IDataObject.GetData(). Show me the file paths and line numbers where these patterns occur.
Copilot 是由 AI 所提供,因此可能會有驚喜和錯誤。 如需詳細資訊,請參閱 Copilot 一般使用常見問題。
使用 AI 將 GetData() 轉換為 TryGetData<T>()
使用 Copilot 將過時的 GetData() 呼叫轉換為新的類型安全 TryGetData<T>() 模式。 此轉換包括適當的錯誤處理,並消除不安全的轉換。
Convert this GetData() clipboard code to use the new TryGetData<T>() method with proper error handling:
[paste your existing GetData() code here]
Make sure to eliminate casting and add appropriate error handling for when the data isn't available.
Copilot 是由 AI 所提供,因此可能會有驚喜和錯誤。 如需詳細資訊,請參閱 Copilot 一般使用常見問題。
使用 AI 將 SetData() 遷移到 SetDataAsJson<T>()
使用 Copilot 將自訂物件儲存體從過時的 SetData() 方法轉換為新的 SetDataAsJson<T>() 方法。 這可確保您的自訂物件正確序列化到剪貼簿。
Take this SetData() clipboard code that stores custom objects:
[paste your existing SetData() code here]
Convert it to use SetDataAsJson<T>() and make the custom types JSON-serializable. Add any necessary System.Text.Json attributes if the types have complex properties.
Copilot 是由 AI 所提供,因此可能會有驚喜和錯誤。 如需詳細資訊,請參閱 Copilot 一般使用常見問題。
使用 AI 建立 JSON 可序列化的資料模型
使用 Copilot 設計可與 SetDataAsJson<T>() 和 TryGetData<T>() 無縫搭配使用的自訂類型。 這包括為需要特殊處理的屬性新增適當的屬性。
Create a JSON-serializable version of this class for clipboard operations:
[paste your existing class definition here]
Make it work with System.Text.Json, add JsonIgnore for sensitive properties, JsonInclude for private fields that should serialize, and JsonPropertyName for any properties that need different names in JSON.
Copilot 是由 AI 所提供,因此可能會有驚喜和錯誤。 如需詳細資訊,請參閱 Copilot 一般使用常見問題。
使用 AI 生成類型安全的封裝方法
使用 Copilot 建立封裝函式方法,以封裝新的剪貼簿 API,並為應用程式的特定資料類型提供乾淨的介面。
Create a type-safe clipboard wrapper class that provides methods for storing and retrieving these custom types:
[list your custom types here]
Use SetDataAsJson<T>() and TryGetData<T>() internally, include proper error handling, and add methods like SavePersonToClipboard() and TryGetPersonFromClipboard().
Copilot 是由 AI 所提供,因此可能會有驚喜和錯誤。 如需詳細資訊,請參閱 Copilot 一般使用常見問題。
使用 AI 創建全面的測試
使用 Copilot 產生測試套件,以驗證剪貼簿移轉是否正常運作,包括來回序列化測試和錯誤處理案例。
Generate comprehensive unit tests for this clipboard code:
[paste your migrated clipboard code here]
Include tests for successful round-trip serialization, handling of null values, error cases when data isn't available, and verification that the migrated code produces the same results as the original for valid scenarios.
Copilot 是由 AI 所提供,因此可能會有驚喜和錯誤。 如需詳細資訊,請參閱 Copilot 一般使用常見問題。
使用 AI 驗證移轉結果
使用 Copilot 檢閱移轉的程式碼,並識別移轉可能未完成的潛在問題或區域。
Review this migrated clipboard code for potential issues:
[paste your migrated code here]
Check for: missing error handling, types that might not serialize properly to JSON, performance concerns with large objects, security issues, and any remaining uses of obsolete methods.
Copilot 是由 AI 所提供,因此可能會有驚喜和錯誤。 如需詳細資訊,請參閱 Copilot 一般使用常見問題。