it-swarm-ko.tech

C #에서 개체를 serialize 할 수 있는지 확인하는 방법

C #의 개체가 serialize 가능한지 확인하는 쉬운 방법을 찾고 있습니다.

아시다시피 ISerializable 인터페이스를 구현하거나 [Serializable]을 클래스 상단에 배치하여 객체를 직렬화 할 수 있습니다.

내가 찾고있는 것은 속성을 얻기 위해 클래스를 반영하지 않고도 이것을 확인할 수있는 빠른 방법입니다. is 문을 사용하면 인터페이스가 빠릅니다.

@Flard의 제안을 사용하여 이것은 내가 생각해 낸 코드입니다. 비명은 더 좋은 방법이 있습니다.

private static bool IsSerializable(T obj)
{
    return ((obj is ISerializable) || (Attribute.IsDefined(typeof (T), typeof (SerializableAttribute))));
}

또는 객체의 유형을 얻은 다음 유형에 IsSerializable 속성을 사용하는 것이 좋습니다.

typeof(T).IsSerializable

이것은 클래스가 다른 클래스를 포함하고 있다면 @pb가 지적한대로 오류를 시도하고 직렬화하고 기다릴 수있는 다른 클래스가 포함되어있는 경우에만 처리하는 클래스 인 것 같습니다.

92
FryHard

Type 클래스에 IsSerializable 클래스가 있습니다.

113
leppie

Serializable 속성에 대해 serialize되는 객체의 그래프에서 모든 유형을 확인해야합니다. 가장 쉬운 방법은 객체를 직렬화하고 예외를 포착하는 것입니다. (그러나 이것이 가장 깨끗한 해결책은 아닙니다). Serial.albe 특성에 대한 Type.IsSerializable 및 검사는 그래프를 고려하지 않습니다.

샘플

[Serializable]
public class A
{
    public B B = new B();
}

public class B
{
   public string a = "b";
}

[Serializable]
public class C
{
    public D D = new D();
}

[Serializable]
public class D
{
    public string d = "D";
}


class Program
{
    static void Main(string[] args)
    {

        var a = typeof(A);

        var aa = new A();

        Console.WriteLine("A: {0}", a.IsSerializable);  // true (WRONG!)

        var c = typeof(C);

        Console.WriteLine("C: {0}", c.IsSerializable); //true

        var form = new BinaryFormatter();
        // throws
        form.Serialize(new MemoryStream(), aa);
    }
}
41
Paul van Brenk

이것은 .NET 3.5 이상에서 업데이트해야 할 수도있는 오래된 질문입니다. 클래스에서 DataContract 특성을 사용하는 경우 Type.IsSerializable은 실제로 false를 반환 할 수 있습니다. 다음은 내가 사용하는 스 니펫입니다.

public static bool IsSerializable(this object obj)
{
    Type t = obj.GetType();

     return  Attribute.IsDefined(t, typeof(DataContractAttribute)) || t.IsSerializable || (obj is IXmlSerializable)

}
16
Mike_G

다른 사람들이 지적했듯이 Type.IsSerializable을 사용하십시오.

객체 그래프의 모든 멤버가 직렬화 가능한지 반영하고 확인하려고 시도하지 않는 것이 좋습니다.

멤버는 직렬화 가능 형식으로 선언 될 수 있지만 실제로 다음과 같은 구성 예에서와 같이 직렬화 가능하지 않은 파생 형식으로 인스턴스화 될 수 있습니다.

[Serializable]
public class MyClass
{
   public Exception TheException; // serializable
}

public class MyNonSerializableException : Exception
{
...
}

...
MyClass myClass = new MyClass();
myClass.TheException = new MyNonSerializableException();
// myClass now has a non-serializable member

따라서 유형의 특정 인스턴스가 직렬화 가능하다고 판단하더라도 일반적으로 모든 인스턴스에서 이것이 사실인지 확신 할 수는 없습니다.

8
Joe
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));

아마도 수중 반사가 가장 간단한 방법일까요?

6
Grad van Horck

다음은 확장 메서드를 사용하여 모든 클래스에서 사용할 수있는 3.5 변형입니다.

public static bool IsSerializable(this object obj)
{
    if (obj is ISerializable)
        return true;
    return Attribute.IsDefined(obj.GetType(), typeof(SerializableAttribute));
}
5
Michael Meadows

이 질문에 대한 답변과 here 답변을 가져 와서 직렬화 할 수없는 유형 목록을 얻도록 수정했습니다. 그렇게하면 어느 것을 표시할지 쉽게 알 수 있습니다.

    private static void NonSerializableTypesOfParentType(Type type, List<string> nonSerializableTypes)
    {
        // base case
        if (type.IsValueType || type == typeof(string)) return;

        if (!IsSerializable(type))
            nonSerializableTypes.Add(type.Name);

        foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
        {
            if (propertyInfo.PropertyType.IsGenericType)
            {
                foreach (var genericArgument in propertyInfo.PropertyType.GetGenericArguments())
                {
                    if (genericArgument == type) continue; // base case for circularly referenced properties
                    NonSerializableTypesOfParentType(genericArgument, nonSerializableTypes);
                }
            }
            else if (propertyInfo.GetType() != type) // base case for circularly referenced properties
                NonSerializableTypesOfParentType(propertyInfo.PropertyType, nonSerializableTypes);
        }
    }

    private static bool IsSerializable(Type type)
    {
        return (Attribute.IsDefined(type, typeof(SerializableAttribute)));
        //return ((type is ISerializable) || (Attribute.IsDefined(type, typeof(SerializableAttribute))));
    }

그리고 당신은 그것을 호출 ...

    List<string> nonSerializableTypes = new List<string>();
    NonSerializableTypesOfParentType(aType, nonSerializableTypes);

비 SerializableTypes가 실행되면 목록이 표시됩니다. 빈 List를 재귀 메서드에 전달하는 것보다이 방법을 사용하는 것이 더 좋습니다. 그렇다면 누군가 나를 교정하십시오.

2
Andy Merrick

VB.NET의 내 솔루션 :

객체의 경우 :

''' <summary>
''' Determines whether an object can be serialized.
''' </summary>
''' <param name="Object">The object.</param>
''' <returns><c>true</c> if object can be serialized; otherwise, <c>false</c>.</returns>
Private Function IsObjectSerializable(ByVal [Object] As Object,
                                      Optional ByVal SerializationFormat As SerializationFormat =
                                                                            SerializationFormat.Xml) As Boolean

    Dim Serializer As Object

    Using fs As New IO.MemoryStream

        Select Case SerializationFormat

            Case Data.SerializationFormat.Binary
                Serializer = New Runtime.Serialization.Formatters.Binary.BinaryFormatter()

            Case Data.SerializationFormat.Xml
                Serializer = New Xml.Serialization.XmlSerializer([Object].GetType)

            Case Else
                Throw New ArgumentException("Invalid SerializationFormat", SerializationFormat)

        End Select

        Try
            Serializer.Serialize(fs, [Object])
            Return True

        Catch ex As InvalidOperationException
            Return False

        End Try

    End Using ' fs As New MemoryStream

End Function

유형의 경우 :

''' <summary>
''' Determines whether a Type can be serialized.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <returns><c>true</c> if Type can be serialized; otherwise, <c>false</c>.</returns>
Private Function IsTypeSerializable(Of T)() As Boolean

    Return Attribute.IsDefined(GetType(T), GetType(SerializableAttribute))

End Function

''' <summary>
''' Determines whether a Type can be serialized.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="Type">The Type.</param>
''' <returns><c>true</c> if Type can be serialized; otherwise, <c>false</c>.</returns>
Private Function IsTypeSerializable(Of T)(ByVal Type As T) As Boolean

    Return Attribute.IsDefined(GetType(T), GetType(SerializableAttribute))

End Function
0
ElektroStudios

예외 객체는 직렬화 가능하지만 다른 예외는 사용하지 않을 수 있습니다. 이것이 내가 WCF System.ServiceModel.FaultException에서 방금 한 것입니다. FaultException은 직렬화 가능하지만 ExceptionDetail은 아닙니다!

그래서 나는 다음을 사용하고 있습니다 :

// Check if the exception is serializable and also the specific ones if generic
var exceptionType = ex.GetType();
var allSerializable = exceptionType.IsSerializable;
if (exceptionType.IsGenericType)
    {
        Type[] typeArguments = exceptionType.GetGenericArguments();
        allSerializable = typeArguments.Aggregate(allSerializable, (current, tParam) => current & tParam.IsSerializable);
    }
 if (!allSerializable)
    {
        // Create a new Exception for not serializable exceptions!
        ex = new Exception(ex.Message);
    }
0
Eric