다음을 통해 공유


.NET 10의 Windows Forms 클립보드 및 DataObject 변경 내용

이 문서에서는 Windows Forms 클립보드 및 끌어서 놓기 작업을 .NET 10의 새 형식 안전 API로 업그레이드하는 방법을 보여 줍니다. 새 Clipboard.TryGetData 형식과 Clipboard.SetDataAsJson<T>(String, T) 메서드를 사용하고, 변경 없이 작동하는 기본 제공 형식을 이해하고, 제거 BinaryFormatter후 사용자 지정 형식 및 레거시 데이터를 처리하기 위한 전략을 검색하는 방법을 알아봅니다.

BinaryFormatter 보안 취약성으로 인해 .NET 9의 런타임에서 제거되었습니다. 이 변경으로 클립보드 및 사용자 지정 개체의 끌어서 놓기 작업이 중단되었습니다. .NET 10에서는 JSON 직렬화 및 형식 안전 메서드를 사용하여 이 기능을 복원하고, 보안을 개선하고, 더 나은 오류 처리 및 프로세스 간 호환성을 제공하는 새로운 API를 도입했습니다.

Clipboard.SetData(String, Object) 는 serialization에 필요한 BinaryFormatter 사용자 지정 형식에서 더 이상 작동하지 않습니다. 이 메서드는 데이터를 즉시 직렬화하는 복사 작업을 기본적으로 수행합니다. 그러나 이제 BinaryFormatter가 제거되었기 때문에, 이를 필요로 하는 형식의 직렬화가 실패합니다. Clipboard.GetData(String) 는 .NET 10에서 사용되지 않습니다. 역직렬화에 BinaryFormatter이(가) 필요하지만 사용이 설정되지 않은 경우, GetData()NotSupportedException 인스턴스를 반환합니다. 형식이 안전한 작업 및 사용자 지정 개체의 JSON serialization에 새 Clipboard.TryGetData 메서드와 Clipboard.SetDataAsJson<T>(String, T) 메서드를 사용합니다.

다음 섹션에서는 자세한 마이그레이션 지침을 제공하고, 변경 없이 작동하는 형식을 설명하고, 새로운 개발 및 레거시 데이터 시나리오를 처리하는 방법을 보여 줍니다.

필수 조건

계속하기 전에 다음 개념을 검토합니다.

  • .NET 9 이전의 클립보드 및 끌어서 놓기 시나리오에서 애플리케이션을 사용하는 BinaryFormatter 방법입니다.
  • 보안 취약성이 BinaryFormatter 제거를 초래했다.
  • System.Text.Json 직렬화 패턴과 그 제한 사항을 다루는 방법.

자세한 내용은 다음 문서를 참조하세요.

BinaryFormatter 제거의 주요 변경 내용

BinaryFormatter.NET 9에서 제거하면 Windows Forms에서 사용자 지정 형식으로 클립보드 및 끌어서 놓기 작업을 처리하는 방식이 기본적으로 변경됩니다. 이러한 변경 내용은 기존 코드 패턴에 영향을 줍니다. 기능을 유지하려면 신중하게 마이그레이션해야 합니다.

사용자 지정 형식이 더 이상 자동으로 직렬화되지 않음

.NET 8 이하에서는 직렬화 가능한 사용자 지정 개체를 호출 SetData()하여 클립보드에 배치할 수 있습니다. BinaryFormatter가 serialization을 자동으로 처리합니다. .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() 예외를 throw하지 않고 메서드가 완료됩니다.
  • 데이터는 클립보드에 배치되지만 필요한 BinaryFormatter형식에 대해서는 serialization이 실패합니다.
  • GetData()으로 데이터를 검색하려는 나중의 시도는 NotSupportedException 인스턴스를 반환하며, 이 인스턴스는 BinaryFormatter가 필요하지만 설정되지 않았음을 나타냅니다.

마이그레이션 지침

SetDataAsJson<T>() 메서드를 사용하거나 수동으로 string 또는 byte[]에 직렬화합니다. 자세한 내용은 사용자 지정 형식 작업 섹션을 참조하세요.

GetData()가 사용되지 않음 - TryGetData<T>()를 대신 사용하세요.

레거시 GetData() 메서드는 .NET 10에서 사용되지 않습니다. 이 메서드는 대부분의 경우 데이터를 성공적으로 반환하지만, BinaryFormatter이(가) 역직렬화에 필요하고 사용하도록 설정되지 않은 경우, GetData()BinaryFormatter이(가) 필요함을 나타내는 인스턴스 NotSupportedException를 반환합니다. 오류 처리 및 형식 안전성 향상을 위해 새 형식 안전 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에는 클립보드 및 끌어서 놓기 작업에 대한 형식 안전성, 더 나은 오류 처리 및 JSON 직렬화 지원을 제공하는 세 가지 새로운 API 제품군이 도입되었습니다.

TryGetData<T>() 메서드

GetData() 메서드가 사용되지 않으므로 TryGetData<T>() 가족이 이를 대체합니다. 클립보드 작업에서 형식 안전 검색을 제공하며, 성공 여부를 명확하게 표시합니다.

기본 형식 안전 검색

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 serialization이 필요하지 않은 형식

많은 기본 제공 .NET 형식은 JSON serialization 또는 BinaryFormatter 지원 없이 클립보드 작업에서 작동합니다. 이러한 형식은 효율적인 스토리지를 제공하고 형식 안전을 유지하는 .NET Remoting Binary Format(NRBF)으로 자동으로 직렬화됩니다.

이러한 형식은 레거시 BinaryFormatter에서 사용하는 것과 동일한 효율적인 이진 형식인 NRBF를 사용합니다. NRBF 직렬화는 다음과 같은 주요 이점을 제공합니다.

  • 컴팩트한 이진 표현: 효율적인 스토리지 및 전송을 지원합니다.
  • 기본 제공 형식 정보: 왕복 작업 중에 정확한 .NET 형식을 유지합니다.
  • 프로세스 간 호환성: 서로 다른 .NET 애플리케이션 간에 작동합니다.
  • 자동 직렬화: 사용자 지정 코드 없이도 형식이 직렬화됩니다.

비고

데이터를 즉시 직렬화하는 복사 작업을 수행하는 것과 같은 SetData() 메서드는 현재 프로세스가 종료된 후에도 클립보드 데이터가 유지되도록 합니다. 형식을 DataObjectSetDataObject(dataObject, copy)을 직접 사용하는 경우 serialization이 발생하는 시기를 제어할 수 있습니다. 매개 변수를 copytrue (기본값)로 설정하면 직렬화가 즉시 수행되고 false 필요할 때까지 serialization을 연기합니다. copyfalse로 설정되고 동일한 프로세스에서 데이터가 검색되는 경우, serialization이 필요하지 않을 수 있지만, 프로세스가 종료되면 데이터는 유지되지 않습니다.

기술 세부 정보는 .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, floatstring.
  • TimeSpanDateTime.

다음 예제에서는 이러한 기본 형식이 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 serialization을 사용합니다.

다음 예제에서는 배열 및 목록을 클립보드에 설정하는 방법을 보여 줍니다.

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, PointF, Rectangle. RectangleF
  • Size, SizeF. Color
  • Bitmap (serialize할 때 상당한 메모리를 사용할 수 있습니다.)

다음 예제에서는 이러한 그래픽 형식을 클립보드 작업과 함께 사용하는 방법을 보여 줍니다.

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가 serialization을 자동으로 처리합니다. 여러 종류의 레코드, 단순 클래스 및 공용 속성이 있는 구조체는 특수한 설정 없이도 원활하게 직렬화됩니다.

특성 없이 작동하는 단순 형식

가장 간단한 사용자 지정 형식에는 특별한 구성이 필요하지 않습니다.

// 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 특성 사용

serialization 동작을 사용자 지정해야 하는 경우에만 특성을 사용합니다 System.Text.Json . System.Text.Json serialization, 특성 및 고급 구성 옵션에 대한 포괄적인 지침은 .NET의 JSON 직렬화 및 역직렬화를 참조하세요.

다음 예제에서는 JSON 특성을 사용하여 serialization을 제어하는 방법을 보여줍니다.

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 지원은 권장되지 않습니다. 새 형식 안전 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.

부조종사에는 AI가 지원되므로 놀라움과 실수가 가능합니다. 자세한 내용은 Copilot 일반 사용 FAQ를 참조하세요.

AI를 사용하여 GetData()를 TryGetData<T>()로 변환

코필로트를 사용하여 사용되지 않는 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.

부조종사에는 AI가 지원되므로 놀라움과 실수가 가능합니다. 자세한 내용은 Copilot 일반 사용 FAQ를 참조하세요.

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.

부조종사에는 AI가 지원되므로 놀라움과 실수가 가능합니다. 자세한 내용은 Copilot 일반 사용 FAQ를 참조하세요.

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.

부조종사에는 AI가 지원되므로 놀라움과 실수가 가능합니다. 자세한 내용은 Copilot 일반 사용 FAQ를 참조하세요.

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().

부조종사에는 AI가 지원되므로 놀라움과 실수가 가능합니다. 자세한 내용은 Copilot 일반 사용 FAQ를 참조하세요.

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.

부조종사에는 AI가 지원되므로 놀라움과 실수가 가능합니다. 자세한 내용은 Copilot 일반 사용 FAQ를 참조하세요.

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.

부조종사에는 AI가 지원되므로 놀라움과 실수가 가능합니다. 자세한 내용은 Copilot 일반 사용 FAQ를 참조하세요.