Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье показано, как обновить операции с буфером обмена и перетаскиванием в Windows Forms до новых API с типизированным доступом в .NET 10. Вы узнаете, как использовать новые Clipboard.TryGetData и Clipboard.SetDataAsJson<T>(String, T) методы, понять, какие встроенные типы работают без изменений, и обнаруживать стратегии обработки пользовательских типов и устаревших данных после удаления BinaryFormatter.
BinaryFormatter удален из среды выполнения в .NET 9 из-за уязвимостей системы безопасности. Это изменение сломало буфер обмена и операции перетаскивания пользовательских объектов. В .NET 10 представлены новые API, использующие сериализацию JSON и методы с безопасностью типов для восстановления этих функций, повышения безопасности и обеспечения более эффективной обработки ошибок и совместимости между процессами.
Clipboard.SetData(String, Object) больше не работает с пользовательскими типами, которые требуют BinaryFormatter для сериализации. Этот метод выполняет операцию копирования (по умолчанию), которая сериализует данные немедленно, но теперь эта сериализация завершается ошибкой для типов, которые требуют BinaryFormatter, так как он был удален.
Clipboard.GetData(String) устарел в .NET 10. Если BinaryFormatter требуется для десериализации, но она не включена, GetData() возвращает NotSupportedException экземпляр. Используйте новые Clipboard.TryGetData и Clipboard.SetDataAsJson<T>(String, T) методы для типобезопасных операций и сериализации JSON пользовательских объектов.
В следующих разделах приведены подробные рекомендации по миграции, объясняющие, какие типы работают без изменений и как обрабатывать новые сценарии разработки и устаревших данных.
Предпосылки
Прежде чем продолжить, ознакомьтесь с этими понятиями:
- Как приложения использовали
BinaryFormatterпри работе с буфером обмена и в сценариях перетаскивания до появления .NET 9. - Уязвимости системы безопасности, которые привели к удалению
BinaryFormatter. - Как работать с
System.Text.Jsonшаблонами сериализации и их ограничениями.
Дополнительные сведения см. в следующих статьях:
- Риски десериализации в использовании BinaryFormatter и связанных типов.
- Руководство по миграции BinaryFormatter.
Изменения, нарушающие совместимость, из-за удаления BinaryFormatter
Удаление BinaryFormatter в .NET 9 коренным образом изменяет способ, которым 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()возвращают экземпляр NotSupportedException, который указывает, чтоBinaryFormatterтребуется, но не включено.
Руководство по миграции
Используйте новый метод 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>()
- Безопасность типов: не требуется приведение типов — метод возвращает точно тот тип, который вы запрашиваете.
- Очистка обработки ошибок: возвращает логический индикатор успешности вместо использования шаблонов null или исключений.
- Готовность к будущему: Предназначено для работы с новыми методами сериализации и поддержкой старых данных.
Определение затронутого кода
Искать:
- Все вызовы
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>()
Эти методы предоставляют возможность автоматической сериализации JSON, используя System.Text.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. Эти типы автоматически сериализуются в бинарном формате удаленного взаимодействия .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,uintulongfloatи .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.Drawing
Распространенные графические типы из пространства имен System.Drawing беспрепятственно работают с буфером обмена и операциями DataObject. Эти типы полезны для приложений, которые работают с визуальными элементами и должны передавать данные, связанные с рисованием между компонентами или приложениями. Помните, что сериализация Bitmap может использовать большой объем памяти, особенно для больших образов. Поддерживаются следующие типы:
-
Point, ,PointFRectangleRectangleF. -
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 сериализации, атрибутам и расширенным параметрам конфигурации см. в статье о сериализации и десериализации JSON в .NET.
В следующем примере показано, как использовать атрибуты 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 (не рекомендуется)
Caution
BinaryFormatter
поддержка не рекомендуется. Используйте его только как временный мост миграции для устаревших приложений, которые не могут немедленно перенестись на новые API с проверкой типов.
Если вы должны продолжать использовать BinaryFormatter для операций буфера обмена в .NET 10, включите ограниченную поддержку с помощью явной конфигурации. Этот подход несет значительные риски безопасности и требует выполнения нескольких шагов.
Полные пошаговые инструкции см. в разделе "Включение поддержки буфера обмена BinaryFormatter" (не рекомендуется). Общие рекомендации по миграции см. в руководстве по миграции BinaryFormatter.
Предупреждения и риски безопасности
BinaryFormatter по сути небезопасный и устаревший по следующим причинам:
- Уязвимости произвольного выполнения кода: злоумышленники могут выполнять вредоносный код во время десериализации, подвергая ваше приложение удалённым атакам.
- Атаки типа "отказ в обслуживании": вредоносные данные буфера обмена могут использовать чрезмерную память или ресурсы ЦП, что приводит к сбоям или нестабильности.
- Риски раскрытия информации: злоумышленники могут извлекать конфиденциальные данные из памяти.
- Нет границ безопасности: формат принципиально небезопасн, и параметры конфигурации не могут защитить его.
Включайте эту поддержку только в качестве временного решения при обновлении приложения для использования новых типобезопасных API.
Подробные рекомендации по безопасности и действия по настройке см. в руководстве по предупреждению и рискам безопасности.
Внедрение ориентированных на безопасность сопоставителей типов
Даже при включении BinaryFormatter необходимо реализовать резолверы типов, чтобы ограничить десериализацию типами, явным образом утвержденными. Следуйте этим рекомендациям:
- Используйте явные списки разрешений. Отклонить любой тип, не утвержденный явным образом.
- Проверьте имена типов. Убедитесь, что имена типов точно соответствуют ожидаемым значениям.
- Ограничение на основные типы. Включите только типы, необходимые для функциональных возможностей буфера обмена.
- Выбрасывать исключения для неизвестных типов. Четко отклоняйте несанкционированные типы.
- Регулярно проверяйте. Аудит и обновление разрешенного списка по мере необходимости.
Полные примеры реализации и примеры кода см. в руководстве по реализации сопоставителей типов, ориентированных на безопасность .
Использование ИИ для переноса кода буфера обмена
Перенос операций буфера обмена с .NET 8 на .NET 10 включает в себя систематические изменения кода в нескольких файлах и классах. Средства искусственного интеллекта, такие как GitHub Copilot, могут ускорить миграцию, определив устаревшие шаблоны, предлагая современные замены и создавая тестовые сценарии. Вместо ручного поиска по базе кода и преобразования каждой операции буфера обмена по отдельности можно использовать ИИ для обработки повторяющихся задач, а также проверки результатов и обработки пограничных вариантов.
В следующих разделах показаны конкретные стратегии подсказки для различных аспектов миграции буфера обмена, от поиска проблемных шаблонов кода до создания надежных JSON-сериализуемых типов и комплексных наборов тестов.
Использование ИИ для выявления устаревших шаблонов буфера обмена
Используйте 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 работает на основе искусственного интеллекта, поэтому возможны сюрпризы и ошибки. Подробности см. в Общие вопросы об использовании Copilot.
Использование ИИ для преобразования 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 работает на основе искусственного интеллекта, поэтому возможны сюрпризы и ошибки. Подробности см. в Общие вопросы об использовании Copilot.
Используйте ИИ для переноса 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 работает на основе искусственного интеллекта, поэтому возможны сюрпризы и ошибки. Подробности см. в Общие вопросы об использовании Copilot.
Использование ИИ для создания моделей данных, сериализуемых в формате 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 работает на основе искусственного интеллекта, поэтому возможны сюрпризы и ошибки. Подробности см. в Общие вопросы об использовании Copilot.
Используйте искусственный интеллект для создания типовобезопасных методов-оберток
Используйте 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 работает на основе искусственного интеллекта, поэтому возможны сюрпризы и ошибки. Подробности см. в Общие вопросы об использовании Copilot.
Использование ИИ для создания комплексных тестов
Используйте 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 работает на основе искусственного интеллекта, поэтому возможны сюрпризы и ошибки. Подробности см. в Общие вопросы об использовании Copilot.
Использование ИИ для проверки результатов миграции
Используйте 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 работает на основе искусственного интеллекта, поэтому возможны сюрпризы и ошибки. Подробности см. в Общие вопросы об использовании Copilot.
Связанный контент
.NET Desktop feedback