C# reflection, cloning - c#

Say I have this class Myclass that contains this method:
public class MyClass
{
public int MyProperty { get; set; }
public int MySecondProperty { get; set; }
public MyOtherClass subClass { get; set; }
public object clone<T>(object original, T emptyObj)
{
FieldInfo[] fis = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
object tempMyClass = Activator.CreateInstance(typeof(T));
foreach (FieldInfo fi in fis)
{
if (fi.FieldType.Namespace != original.GetType().Namespace)
fi.SetValue(tempMyClass, fi.GetValue(original));
else
fi.SetValue(tempMyClass, this.clone(fi.GetValue(original), fi.GetValue(original)));
}
return tempMyClass;
}
}
Then this class:
public class MyOtherClass
{
public int MyProperty777 { get; set; }
}
when I do this:
MyClass a = new MyClass {
MyProperty = 1,
MySecondProperty = 2,
subClass = new MyOtherClass() { MyProperty777 = -1 }
};
MyClass b = a.clone(a, a) as MyClass;
how come on the second call to clone, T is of type object and not of type MyOtherClass

Your second (recursive) call to clone passes the result of GetValue as the second argument, which is of type object, and hence T is object.
i.e.
fi.SetValue(tempMyClass, this.clone(fi.GetValue(original), fi.GetValue(original)));
The result of GetValue on a FieldInfo is an object.
Given that you pass the same thing twice in all cases, the design of the clone method is possibly wrong. You probably don't need generics there. Just use obj.GetType() to get the type information of the second argument (if indeed you really need a second argument).
It would make more sense to constrain the return type using generics, so that the cast isn't necessary on the calling side. Also you could make Clone into an extension method so it could apply to anything.
On the other hand, the thing you're trying to do (an automatic deep clone) is unlikely to be generally useful. Most classes end up hold references to things that they don't own, so if you clone such an object, you end up accidentally cloning half of your application framework.

Try this:
public static class Cloner
{
public static T clone(this T item)
{
FieldInfo[] fis = item.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
object tempMyClass = Activator.CreateInstance(item.GetType());
foreach (FieldInfo fi in fis)
{
if (fi.FieldType.Namespace != item.GetType().Namespace)
fi.SetValue(tempMyClass, fi.GetValue(item));
else
{
object obj = fi.GetValue(item);
fi.SetValue(tempMyClass, obj.clone());
}
}
return (T)tempMyClass;
}
}
MyClass b = a.clone() as MyClass;

Best way to clone an instance of a class is to create a delegate to do it. Indeed, delegate produced by linq expression can access private/internal/protected and public fields. Delegate can be created only once. Keep it in static field in generic class to take benefit of generic lookup resolution instead of dictionary
/// <summary>
/// Help to find metadata from expression instead of string declaration to improve reflection reliability.
/// </summary>
static public class Metadata
{
/// <summary>
/// Identify method from method call expression.
/// </summary>
/// <typeparam name="T">Type of return.</typeparam>
/// <param name="expression">Method call expression.</param>
/// <returns>Method.</returns>
static public MethodInfo Method<T>(Expression<Func<T>> expression)
{
return (expression.Body as MethodCallExpression).Method;
}
}
/// <summary>
/// Help to find metadata from expression instead of string declaration to improve reflection reliability.
/// </summary>
/// <typeparam name="T">Type to reflect.</typeparam>
static public class Metadata<T>
{
/// <summary>
/// Cache typeof(T) to avoid lock.
/// </summary>
static public readonly Type Type = typeof(T);
/// <summary>
/// Only used as token in metadata expression.
/// </summary>
static public T Value { get { throw new InvalidOperationException(); } }
}
/// <summary>
/// Used to clone instance of any class.
/// </summary>
static public class Cloner
{
/// <summary>
/// Define cloner implementation of a specific type.
/// </summary>
/// <typeparam name="T">Type to clone.</typeparam>
static private class Implementation<T>
where T : class
{
/// <summary>
/// Delegate create at runtime to clone.
/// </summary>
static public readonly Action<T, T> Clone = Cloner.Implementation<T>.Compile();
/// <summary>
/// Way to emit delegate without static constructor to avoid performance issue.
/// </summary>
/// <returns>Delegate used to clone.</returns>
static public Action<T, T> Compile()
{
//Define source and destination parameter used in expression.
var _source = Expression.Parameter(Metadata<T>.Type);
var _destination = Expression.Parameter(Metadata<T>.Type);
//Clone method maybe need more than one statement.
var _body = new List<Expression>();
//Clone all fields of entire hierarchy.
for (var _type = Metadata<T>.Type; _type != null; _type = _type.BaseType)
{
//Foreach declared fields in current type.
foreach (var _field in _type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
//Assign destination field using source field.
_body.Add(Expression.Assign(Expression.Field(_destination, _field), Expression.Field(_source, _field)));
}
}
//Compile expression to provide clone method.
return Expression.Lambda<Action<T, T>>(Expression.Block(_body), _source, _destination).Compile();
}
}
/// <summary>
/// Keep instance of generic definition of clone method to improve performance in reflection call case.
/// </summary>
static private readonly MethodInfo Method = Metadata.Method(() => Cloner.Clone(Metadata<object>.Value)).GetGenericMethodDefinition();
static public T Clone<T>(T instance)
where T : class
{
//Nothing to clone.
if (instance == null) { return null; }
//Identify instace type.
var _type = instance.GetType();
//if T is an interface, instance type might be a value type and it is not needed to clone value type.
if (_type.IsValueType) { return instance; }
//Instance type match with generic argument.
if (_type == Metadata<T>.Type)
{
//Instaitate clone without executing a constructor.
var _clone = FormatterServices.GetUninitializedObject(_type) as T;
//Call delegate emitted once by linq expreesion to clone fields.
Cloner.Implementation<T>.Clone(instance, _clone);
//Return clone.
return _clone;
}
//Reflection call case when T is not target Type (performance overhead).
return Cloner.Method.MakeGenericMethod(_type).Invoke(null, new object[] { instance }) as T;
}
}

First of all I agree that clone method should be static, but I don't think that
object tempMyClass = Activator.CreateInstance(typeof(T));
is a good idea. I think that better way is to use type of original and get rid of emptyObject parameter at all.
object tempMyClass = Activator.CreateInstance(original.GetType());
Also you have to GetFields on original not on this.
So my method would be
public static T clone<T>(T original)
{
T tempMyClass = (T)Activator.CreateInstance(original.GetType());
FieldInfo[] fis = original.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fi in fis)
{
object fieldValue = fi.GetValue(original);
if (fi.FieldType.Namespace != original.GetType().Namespace)
fi.SetValue(tempMyClass, fieldValue);
else
fi.SetValue(tempMyClass, clone(fieldValue));
}
return tempMyClass;
}
Note that I use original.GetType() anyway as inner call would have type T=Object anyway. Used generic type is determined at compilation time and it would be Object as return type of fi.GetValue.
You can move this static method to some static helper class.
As a side note I'd like to say that this implementation of "deep" clone will not work properly if there is some collection-type field (or any standard mutable composite field) in one of classes in your namespace.

I tried to clone an entity framework object with the examples posted here but nothing worked.
I made an extension method with a different way and now I can clone EF objects:
public static T CloneObject<T>(this T source)
{
if (source == null || source.GetType().IsSimple())
return source;
object clonedObj = Activator.CreateInstance(source.GetType());
var properties = source.GetType().GetProperties();
foreach (var property in properties)
{
try
{
property.SetValue(clonedObj, property.GetValue(source));
}
catch { }
}
return (T)clonedObj;
}
public static bool IsSimple(this Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// nullable type, check if the nested type is simple.
return IsSimple(type.GetGenericArguments()[0]);
}
return !type.IsClass
|| type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
I didn't check for the array cases but you can add some code for that too (like in this link):
else if (type.IsArray)
{
Type typeElement = Type.GetType(type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copiedArray = Array.CreateInstance(typeElement, array.Length);
for (int i = 0; i < array.Length; i++)
{
// Get the deep clone of the element in the original array and assign the
// clone to the new array.
copiedArray.SetValue(CloneProcedure(array.GetValue(i)), i);
}
return copiedArray;
}

Related

Why doesn't Type.GetFields() return backing fields in a base class?

In C#, if you use Type.GetFields() with a type representing a derived class, it will return a) all explicitly declared fields in the derived class, b) all backing fields of automatic properties in the derived class and c) all explicitly declared fields in the base class.
Why are the d) backing fields of automatic properties in the base class missing?
Example:
public class Base {
public int Foo { get; set; }
}
public class Derived : Base {
public int Bar { get; set; }
}
class Program {
static void Main(string[] args) {
FieldInfo[] fieldInfos = typeof(Derived).GetFields(
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.FlattenHierarchy
);
foreach(FieldInfo fieldInfo in fieldInfos) {
Console.WriteLine(fieldInfo.Name);
}
}
}
This will show only the backing field of Bar, not Foo.
A field being a backing field has no influence on reflection. The only relevant property of backing fields is that they are private.
Reflection functions don't return private members of base classes, even if you use FlattenHierarchy. You will need to loop manually over your class hierarchy and ask for private fields on each one.
I think FlattenHierarchy is written with the intent to show all members visible to code in the class you look at. So base members can be hidden/shadowed by members with the same name in a more derived class and private members are not visible at all.
Here is a revised version using HashSet:
public static FieldInfo[] GetFieldInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
{
FieldInfo[] fieldInfos = type.GetFields(bindingFlags);
// If this class doesn't have a base, don't waste any time
if (type.BaseType == typeof(object))
{
return fieldInfos;
}
else
{ // Otherwise, collect all types up to the furthest base class
var currentType = type;
var fieldComparer = new FieldInfoComparer();
var fieldInfoList = new HashSet<FieldInfo>(fieldInfos, fieldComparer);
while (currentType != typeof(object))
{
fieldInfos = currentType.GetFields(bindingFlags);
fieldInfoList.UnionWith(fieldInfos);
currentType = currentType.BaseType;
}
return fieldInfoList.ToArray();
}
}
private class FieldInfoComparer : IEqualityComparer<FieldInfo>
{
public bool Equals(FieldInfo x, FieldInfo y)
{
return x.DeclaringType == y.DeclaringType && x.Name == y.Name;
}
public int GetHashCode(FieldInfo obj)
{
return obj.Name.GetHashCode() ^ obj.DeclaringType.GetHashCode();
}
}
Thanks go to #CodeInChaos for the quick and complete answer!
In case anyone else stumbles across this, here's a quick workaround that follows the fields up to the furthest base class.
/// <summary>
/// Returns all the fields of a type, working around the fact that reflection
/// does not return private fields in any other part of the hierarchy than
/// the exact class GetFields() is called on.
/// </summary>
/// <param name="type">Type whose fields will be returned</param>
/// <param name="bindingFlags">Binding flags to use when querying the fields</param>
/// <returns>All of the type's fields, including its base types</returns>
public static FieldInfo[] GetFieldInfosIncludingBaseClasses(
Type type, BindingFlags bindingFlags
) {
FieldInfo[] fieldInfos = type.GetFields(bindingFlags);
// If this class doesn't have a base, don't waste any time
if(type.BaseType == typeof(object)) {
return fieldInfos;
} else { // Otherwise, collect all types up to the furthest base class
var fieldInfoList = new List<FieldInfo>(fieldInfos);
while(type.BaseType != typeof(object)) {
type = type.BaseType;
fieldInfos = type.GetFields(bindingFlags);
// Look for fields we do not have listed yet and merge them into the main list
for(int index = 0; index < fieldInfos.Length; ++index) {
bool found = false;
for(int searchIndex = 0; searchIndex < fieldInfoList.Count; ++searchIndex) {
bool match =
(fieldInfoList[searchIndex].DeclaringType == fieldInfos[index].DeclaringType) &&
(fieldInfoList[searchIndex].Name == fieldInfos[index].Name);
if(match) {
found = true;
break;
}
}
if(!found) {
fieldInfoList.Add(fieldInfos[index]);
}
}
}
return fieldInfoList.ToArray();
}
}
Be aware that I'm manually comparing the fields in a nested for loop. If you have deeply nested classes or monstrously big classes, feel free to use a HashSet<> instead.
EDIT: Also be aware that this doesn't search types further down in the inheritance chain. In my case I know that I'm at the most derived type when callling the method.

Attributes and classes

I'm searching to how can I know inside an attribute definition if the class I apply the attribute to, has another attribute
Example:
[My1Attribute]
public class MyClass
{
[My2Attribute]
int aux{get;set;}
}
internal sealed class My1Attribute : Attribute
{
public My1Attribute
{
// How can I Know if 'MyClass' has My2Attribute applied ???
}
}
The attribute itself will not know about the class to which it's attached. You will need to use some other service/helper function/whatever to pair them up.
However, you might find the following useful:
public static bool HasAttribute<T, TAttribute>() where TAttribute : Attribute
{
return typeof (T).GetCustomAttributes(typeof (TAttribute), true).Any();
}
Edit: For finding attributes on member fields
/// <summary>
/// Returns all the (accessible) fields or properties that for a given type that
/// have the "T" attribute declared on them.
/// </summary>
/// <param name="type">Type object to search</param>
/// <returns>List of matching members</returns>
public static List<MemberInfo> FindMembers<T>(Type type) where T : Attribute
{
return FindMembers<T>(type, MemberTypes.Field | MemberTypes.Property);
}
/// <summary>
/// Returns all the (accessible) fields or properties that for a given type that
/// have the "T" attribute declared on them.
/// </summary>
/// <param name="type">Type object to search</param>
/// <returns>List of matching members</returns>
public static List<MemberInfo> FindMembers<T>(Type type, MemberTypes memberTypesFlags) where T : Attribute
{
const BindingFlags FieldBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
List<MemberInfo> members = new List<MemberInfo>();
members.AddRange(type.FindMembers(
memberTypesFlags,
FieldBindingFlags,
HasAttribute<T>, // Use delegate from below...
null)); // This arg is ignored by the delegate anyway...
return members;
}
public static bool HasAttribute<T>(MemberInfo mi) where T : Attribute
{
return GetAttribute<T>(mi) != null;
}
public static bool HasAttribute<T>(MemberInfo mi, object o) where T : Attribute
{
return GetAttribute<T>(mi) != null;
}
In this instance, you would need to define your rules about how you determine what members you are going to check. In your example, you're using the attributed decorated on a property, so given that you have an instance of Type for MyClass (e.g. typeof(MyClass)), you can grab the properties:
var property = type.GetProperty("aux", BindingFlags.Instance | BindingFlags.NonPublic);
if (property.IsDefined(typeof(My1Attribute)))
{
// Property has the attribute.
}
(This is assuming you actually want to grab that non-public instance property, if not adjust your BindingFlags).
If you actually want to use the attribute:
var attib = property.GetCustomAttributes(typeof(My1Attribute), false)[0];
// Do something with the attribute instance.
Have you tried Reflection?, plus here's a related question that you might find helpful: How to check if C# class has security attribute used
I am guessing you mean in general find out if any class with MyAttribute1 has My2Attribute (rather than specifically MyClass). The only way I can think of doing it is getting a list of all classes from reflection and iterating through them checking which ones have Attribute1 and then check if they have Attribute2.
I don't think you can do anything clever like automatically retrieve a list of classes with current attribute.

Get generic type of call to method in dynamic object

I'm starting to work with dynamic objects in .Net and I can't figure out how to do something.
I have a class that inherits from DynamicObject, and I override the TryInvokeMember method.
e.g.
class MyCustomDynamicClass : DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
// I want to know here the type of the generic argument
}
}
And inside that method I want to know the type (if any) of the generic arguments in the invocation.
e.g.
If I invoke the following code, I want to get the value of System.Boolean and System.Int32 inside the overrided method of my dynamic object
dynamic myObject = new MyCustomDynamicClass();
myObject.SomeMethod<bool>("arg");
myObject.SomeOtherMethod<int>("arg");
Currently if I place a breakpoint inside the overrided method I can get the name of the method being invoked ("SomeMethod" and "SomeOtherMethod", and also the values of the arguments, but not the generic types).
How can I get these values?
Thanks!
Actually I looked through the hierarchy of the binder and found a property with the needed values in the internal fields of the object.
The problem is that the property isn't exposed because it uses C#-specific code/classes, therefore the properties must be accessed using Reflection.
I found the code in this japanese blog: http://neue.cc/category/programming (I don't read any japanese, therefore I'm not sure if the author actually describes this same issue
Here's the snippet:
var csharpBinder = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
var typeArgs = (csharpBinder.GetProperty("TypeArguments").GetValue(binder, null) as IList<Type>);
typeArgs is a list containing the types of the generic arguments used when invoking the method.
Hope this helps someone else.
A bit of googling and I have quite generic solution for .NET and Mono:
/// <summary>Framework detection and specific implementations.</summary>
public static class FrameworkTools
{
private static bool _isMono = Type.GetType("Mono.Runtime") != null;
private static Func<InvokeMemberBinder, IList<Type>> _frameworkTypeArgumentsGetter = null;
/// <summary>Gets a value indicating whether application is running under mono runtime.</summary>
public static bool IsMono { get { return _isMono; } }
static FrameworkTools()
{
_frameworkTypeArgumentsGetter = CreateTypeArgumentsGetter();
}
private static Func<InvokeMemberBinder, IList<Type>> CreateTypeArgumentsGetter()
{
if (IsMono)
{
var binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder");
if (binderType != null)
{
ParameterExpression param = Expression.Parameter(typeof(InvokeMemberBinder), "o");
return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
Expression.TypeAs(
Expression.Field(
Expression.TypeAs(param, binderType), "typeArguments"),
typeof(IList<Type>)), param).Compile();
}
}
else
{
var inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
if (inter != null)
{
var prop = inter.GetProperty("TypeArguments");
if (!prop.CanRead)
return null;
var objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o");
return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
Expression.TypeAs(
Expression.Property(
Expression.TypeAs(objParm, inter),
prop.Name),
typeof(IList<Type>)), objParm).Compile();
}
}
return null;
}
/// <summary>Extension method allowing to easyly extract generic type arguments from <see cref="InvokeMemberBinder"/>.</summary>
/// <param name="binder">Binder from which get type arguments.</param>
/// <returns>List of types passed as generic parameters.</returns>
public static IList<Type> GetGenericTypeArguments(this InvokeMemberBinder binder)
{
// First try to use delegate if exist
if (_frameworkTypeArgumentsGetter != null)
return _frameworkTypeArgumentsGetter(binder);
if (_isMono)
{
// In mono this is trivial.
// First we get field info.
var field = binder.GetType().GetField("typeArguments", BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
// If this was a success get and return it's value
if (field != null)
return field.GetValue(binder) as IList<Type>;
}
else
{
// In this case, we need more aerobic :D
// First, get the interface
var inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
if (inter != null)
{
// Now get property.
var prop = inter.GetProperty("TypeArguments");
// If we have a property, return it's value
if (prop != null)
return prop.GetValue(binder, null) as IList<Type>;
}
}
// Sadly return null if failed.
return null;
}
}
Have fun. By the way Impromptu is cool, but I can't use it.
The open source framework Dynamitey can call properties that internal/protected/private using the DLR and thus works with Silverlight. But it get's a little tricky with interface explicit members as you have to use the actual full name of the member on the the type, rather than the interface member name. So you can do:
var typeArgs = Dynamic.InvokeGet(binder, "Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments")
as IList<Type>;

Get primitive, complex, ArrayEnumerable types

I have a separate class for each of my database entities and when I create an object of my class to reference the properties of a class it returns a circular reference which contains properties of other entities too that are related via FK ... to remove the circular reference I want to first make a copy of the object through "context proxy object" copy and then get the primitive, complex, arrayEnumerable types of that object and strip off these types from the object and then the object get returned by web service....
Sounds like a recursive shallow clone. I've used the following but only one level deep.
public static class EntityBaseExtensions
{
/// <summary>
/// Description: Creates a non-recursive shallow copy of an entity, only including public instance properties decorated with ColumnAttribute.
/// This will return an object without entity references.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <returns>A non-recursive shallow copy of a LINQ entity</returns>
public static T ShallowClone<T>(this T source) where T : EntityBaseClass
{
// create an object to copy values into
T destination = Activator.CreateInstance<T>();
// get source and destination property infos for all public instance
PropertyInfo[] sourcePropInfos = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] destinationPropInfos = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo sourcePropInfo in sourcePropInfos)
{
if (Attribute.GetCustomAttribute(sourcePropInfo, typeof(ColumnAttribute), false) != null)
{
PropertyInfo destPropInfo = destinationPropInfos.Where(pi => pi.Name == sourcePropInfo.Name).First();
destPropInfo.SetValue(destination, sourcePropInfo.GetValue(source, null), null);
}
}
return destination;
}
}

How to check if an object is serializable in C#

I am looking for an easy way to check if an object in C# is serializable.
As we know you make an object serializable by either implementing the ISerializable interface or by placing the [Serializable] at the top of the class.
What I am looking for is a quick way to check this without having to reflect the class to get it's attributes. The interface would be quick using an is statement.
Using #Flard's suggestion this is the code that I have come up with, scream is there is a better way.
private static bool IsSerializable(T obj)
{
return ((obj is ISerializable) || (Attribute.IsDefined(typeof (T), typeof (SerializableAttribute))));
}
Or even better just get the type of the object and then use the IsSerializable property on the type:
typeof(T).IsSerializable
Remember though this this seems to only just the class that we are dealing with if the class contains other classes you probably want to check them all or try and serialize and wait for errors as #pb pointed out.
You have a lovely property on the Type class called IsSerializable.
You're going to have to check all types in the graph of objects being serialized for the serializable attribute. The easiest way is to try to serialize the object and catch the exception. (But that's not the cleanest solution). Type.IsSerializable and checking for the serializalbe attribute don't take the graph into account.
Sample
[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);
}
}
This is an old question, that may need to be updated for .NET 3.5+. Type.IsSerializable can actually return false if the class uses the DataContract attribute. Here is a snippet i use, if it stinks, let me know :)
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.
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
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);
}

Categories