개체가 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)
}
Use Type.IsSerializable as others have pointed out.
It's probably not worth attempting to reflect and check if all members in the object graph are serializable.
A member could be declared as a serializable type, but in fact be instantiated as a derived type that is not serializable, as in the following contrived example:
[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
Therefore, even if you determine that a specific instance of your type is serializable, you can't in general be sure this will be true of all instances.
Attribute.IsDefined(typeof (YourClass), typeof (SerializableAttribute));
Probably involves reflection underwater, but the most simple way?
Here's a 3.5 variation that makes it available to all classes using an extension method.
public static bool IsSerializable(this object obj)
{
if (obj is ISerializable)
return true;
return Attribute.IsDefined(obj.GetType(), typeof(SerializableAttribute));
}
I took the answer on this question and the answer here and modified it so you get a List of types that aren't serializable. That way you can easily know which ones to mark.
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))));
}
And then you call it...
List<string> nonSerializableTypes = new List<string>();
NonSerializableTypesOfParentType(aType, nonSerializableTypes);
When it runs, nonSerializableTypes will have the list. There may be a better way of doing this than passing in an empty List to the recursive method. Someone correct me if so.
The exception object might be serializable , but using an other exception which is not. This is what I just had with WCF System.ServiceModel.FaultException: FaultException is serializable but ExceptionDetail is not!
So I am using the following:
// 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);
}
My solution, in VB.NET:
For Objects:
''' <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
For Types:
''' <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
참고URL : https://stackoverflow.com/questions/81674/how-to-check-if-an-object-is-serializable-in-c-sharp
'developer tip' 카테고리의 다른 글
기본 패키지에서 Java 클래스에 액세스하는 방법은 무엇입니까? (0) | 2020.08.30 |
---|---|
자바 스크립트 지수 (0) | 2020.08.30 |
jQuery .hasClass () 대 .is () (0) | 2020.08.30 |
Grunt 태스크에서 명령 실행 (0) | 2020.08.30 |
Pandas : 데이터 프레임을 인덱싱하는 동안 여러 조건-예기치 않은 동작 (0) | 2020.08.30 |