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

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



답변

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


답변

직렬화 가능한 속성에 대해 직렬화되는 객체의 그래프에서 모든 유형을 확인해야합니다. 가장 쉬운 방법은 객체를 직렬화하고 예외를 포착하는 것입니다. (그러나 그것은 가장 깨끗한 해결책이 아닙니다). 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);
    }
}


답변

이것은 .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)

}


답변

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

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


답변

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

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


답변

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

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


답변

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

    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에 목록이 있습니다. 빈 목록을 재귀 메서드에 전달하는 것보다 더 나은 방법이있을 수 있습니다. 그렇다면 누군가 나를 바로 잡습니다.