كيفية التحقق مما إذا كان الكائن قابلاً للتسلسل في C#

StackOverflow https://stackoverflow.com/questions/81674

  •  09-06-2019
  •  | 
  •  

سؤال

أنا أبحث عن طريقة سهلة للتحقق مما إذا كان الكائن في C# قابلاً للتسلسل.

كما نعلم، فإنك تجعل كائنًا قابلاً للتسلسل إما عن طريق تنفيذ ملف قابل للتسلسل الواجهة أو عن طريق وضع [قابل للتسلسل] في الجزء العلوي من الفصل.

ما أبحث عنه هو طريقة سريعة للتحقق من ذلك دون الحاجة إلى عكس الفصل للحصول على سماته.ستكون الواجهة سريعة باستخدام ملف يكون إفادة.

باستخدام اقتراح @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.هذا مقتطف أستخدمه، إذا كانت رائحته كريهة، أخبرني :)

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 القائمة.قد تكون هناك طريقة أفضل للقيام بذلك بدلاً من تمرير قائمة فارغة إلى الطريقة العودية.شخص يصحح لي إذا كان الأمر كذلك.

قد يكون كائن الاستثناء قابلاً للتسلسل، ولكن باستخدام استثناء آخر غير قابل للتسلسل.هذا ما حصلت عليه للتو مع 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);
    }

الحل الخاص بي في 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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top