كيفية التحقق مما إذا كان الكائن قابلاً للتسلسل في C#
-
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