개체가 C #에서 직렬화 가능한지 확인하는 방법


94

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

우리가 알고 있듯이 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가 지적한대로 오류를 시도하고 직렬화하고 기다릴 수 있습니다.


1
obj의 필드가 직렬화 가능하지 않을 때 실패하여 죄송합니다. 내 샘플을 참조하십시오.
Paul van Brenk

나는 이것이 훨씬 더 나은 접근이라고 생각합니다 : stackoverflow.com/questions/236599/…
xero

"ISerializable 인터페이스를 구현하거나 [Serializable]을 클래스 맨 위에 배치하여 개체를 직렬화 할 수 있도록합니다."라는 문은 거짓입니다. 개체를 직렬화 할 수 있으려면 해당 클래스가 SerializableAttribute를 선언해야합니다. ISerializable을 구현하면 프로세스를 더 잘 제어 할 수 있습니다.
Mishax

답변:


115

Type라는 클래스 에 멋진 속성이 IsSerializable있습니다.


7
이것은 Serializable 속성이 클래스에 첨부되었는지 여부를 알려줍니다.
Fatema

37
그의 요점은 포함하는 유형이 있더라도 해당 객체의 멤버가 직렬화 가능하지 않을 수 있다는 것입니다. 권리? 그 객체 멤버를 재귀 적으로 드릴하고 각 멤버를 확인해야하는 경우가 아닌가?
Brian Sweeney

3
목록 <SomeDTO>에 대한 예를 들어 IsSerializable는 SomeDTO가 직렬화되어 있지 않은 경우 사실 짝수
사이먼 Dowdeswell 씨

43

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

견본

[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);
    }
}

비용이 너무 크지 않으면이 방법이 최선이라고 생각합니다. 서로 다른 직렬화 요구 사항 (binary, xml)을 확인할 수 있습니다. 또한 객체에는 직렬화를 중단하고 런타임에 변경 될 수있는 상속 된 클래스 유형으로 교체 할 수있는 일반 멤버가있을 수 있습니다. List (Of baseclass)는 직렬화 할 수없는 subclassA의 항목을 추가 할 수 있습니다. 여기서 baseclass와 subclassB는 직렬화 가능합니다.
VoteCoffee

이 답변은 복제를 사용하여 직렬화가 왕복 할 수 있는지 확인합니다. 직렬화가 일부 구성원을 설정하지 않을 것으로 예상되지만 경우에 따라 과잉 일 수 있습니다. stackoverflow.com/questions/236599/…
VoteCoffee

18

이것은 .NET 3.5 이상에 대해 업데이트해야 할 수있는 오래된 질문입니다. Type.IsSerializable은 클래스가 DataContract 특성을 사용하는 경우 실제로 false를 반환 할 수 있습니다. 다음은 내가 사용하는 스 니펫입니다. 냄새가 나면 알려주세요. :)

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

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

}

1
오래된 질문과 오래된 답변이지만 이것은 매우 사실입니다! Type.IsSerializable은 부분적으로 만 작동하는 솔루션입니다. 사실, 요즘 얼마나 ​​많은 사람들이 WCF와 DataContracts를 사용하고 있는지 감안할 때 실제로는 매우 열악한 솔루션입니다!
Jaxidian

obj가 null로 들어 오면 어떻게 되나요?
N73k

@ N73k null확인하고 반환하면 true?
FredM

9

다른 사람들이 지적한대로 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

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


6
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));

아마도 수중 반사를 포함하지만 가장 간단한 방법은 무엇입니까?


5

확장 메서드를 사용하여 모든 클래스에서 사용할 수 있도록하는 3.5 변형이 있습니다.

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

2

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

    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);

실행되면 nonSerializableTypes에 목록이 있습니다. 빈 목록을 재귀 메서드에 전달하는 것보다 더 나은 방법이있을 수 있습니다. 그렇다면 누군가 나를 바로 잡습니다.


0

예외 객체는 직렬화 가능할 수 있지만 그렇지 않은 다른 예외를 사용합니다. 이것은 방금 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

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.