How to execute a private static method with optional parameters via reflection? - c#

I have a class with a private static method with an optional parameter. How do I invoke it from another class via Reflection? There is a similar question, but it does not address static method or optional parameters.
public class Foo {
private static void Bar(string key = "") {
// do stuff
}
}
How do I invoke Foo.Bar("test") and Foo.Bar() (e.g. without passing the optional parameter)?

Optional parameter values in C# are compiled by injection those values at the callsite. I.e. even though your code is
Foo.Bar()
The compiler actually generates a call like
Foo.Bar("")
When finding the method you need to treat the optional parameters as regular parameters.
var method = typeof(Foo).GetMethod("Bar", BindingFlags.Static | BindingFlags.NonPublic);
If you know exactly what values you want to invoke the method with you can do:
method.Invoke(obj: null, parameters: new object[] { "Test" });
If you only have some of the parameters and want to honor the values of the default ones you have to inspect the method's ParameterInfo objects to see if the parameters are optional and what those values are. For example to print out the default values of those parameters you could use the following code:
foreach (ParameterInfo pi in method.GetParameters())
{
if (pi.IsOptional)
{
Console.WriteLine(pi.Name + ": " + pi.DefaultValue);
}
}

Using this class
public class Foo
{
private static void Bar(string key = "undefined key", string value = "undefined value")
{
Console.WriteLine(string.Format("The key is '{0}'", key));
Console.WriteLine(string.Format("The value is '{0}'", value));
}
}
You can use the following code to call it with the default values
MethodInfo mi = typeof(Foo).GetMethod("Bar", BindingFlags.NonPublic | BindingFlags.Static);
ParameterInfo[] pis = mi.GetParameters();
object[] parameters = new object[pis.Length];
for (int i = 0; i < pis.Length; i++)
{
if (pis[i].IsOptional)
{
parameters[i] = pis[i].DefaultValue;
}
}
mi.Invoke(null, parameters);
If the method had some non-optional parameters, you will have to insert them into the parameters array before invoking the method.
E.g
private static void Bar(int number, string key = "undefined key", string value = "undefined")
Would require you to do
parameters[0] = "23"
Before invoking

Something i wrote for my unit tests:
/// <summary>
/// Attempts to execute a function and provide the result value against the provided source object even if it is private and/or static. Just make sure to provide the correct BindingFlags to correctly identify the function.
/// </summary>
/// <typeparam name="TReturn">The expected return type of the private method.</typeparam>
/// <param name="type">The object's Type that contains the private method.</param>
/// <param name="source">The object that contains the function to invoke. If looking for a static function, you can provide "null".</param>
/// <param name="methodName">The name of the private method to run.</param>
/// <param name="flags">Binding flags used to search for the function. Example: (BindingFlags.NonPublic | BindingFlags.Static) finds a private static method.</param>
/// <param name="output">The invoked function's return value.</param>
/// <param name="methodArgs">The arguments to pass into the private method.</param>
/// <returns>Returns true if function was found and invoked. False if function was not found.</returns>
private static bool TryInvokeMethod<TReturn>(Type type, object source, string methodName, BindingFlags flags, out TReturn output, params object[] methodArgs)
{
var method = type.GetMethod(methodName, flags);
if(method != null)
{
output = (TReturn)method.Invoke(source, methodArgs);
return true;
}
// Perform some recursion to walk the inheritance.
if(type.BaseType != null)
{
return TryInvokeMethod(type.BaseType, source, methodName, flags, out output, methodArgs);
}
output = default(TReturn);
return false;
}
Then call it like so to invoke a private static function:
var success = TryInvokeMethod(typeof(Foo), null, "MyPrivateStaticFunc", BindingFlags.NonPublic | BindingFlags.Static, out result, arg1ToPass);
Disclaimer: I use this for functions with a return value only. Attempting to execute a method with no return value will throw an exception.

Related

Can anyone explain to me how I can use Func<T, T, bool>? validateValue = null) validation in the Xamarin Community Toolkit ObservableObject?

I've not been able to find any examples at all for this.
Here is what I am currently doing:
public partial class RenameGroupPopupViewModel
{
private string _newGroupName;
public string NewGroupName
{
get => _newGroupName;
set => SetProperty(ref _newGroupName, value);
}
}
In ObservableObject.cs there is a parameter validateValue but I do not know or understand how to use it.
I would like to try using the Func<T, T, bool>? validateValue = null) to call a method called ValidateName that would check if the value is set to "default" and if so then return false so the value would not be set.
Here is the full code for the class:
ObservableObject.cs
Here is the code snippet from
/// <summary>
/// Sets the property.
/// </summary>
/// <returns><c>true</c>, if property was set, <c>false</c> otherwise.</returns>
/// <param name="backingStore">Backing store.</param>
/// <param name="value">Value.</param>
/// <param name="validateValue">Validates value.</param>
/// <param name="propertyName">Property name.</param>
/// <param name="onChanged">On changed.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
protected virtual bool SetProperty<T>(
ref T backingStore,
T value,
[CallerMemberName] string propertyName = "",
Action? onChanging = null,
Action? onChanged = null,
Func<T, T, bool>? validateValue = null)
{
// if value didn't change
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
// if value changed but didn't validate
if (validateValue != null && !validateValue(backingStore, value))
return false;
onChanging?.Invoke();
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
I realize I have to supply a function for the validation but I am not sure how to specify this and should it be a normal kind of method or a delegate? Here is the functionality I need:
private bool ValidateName(string groupName)
{
if (groupName == "default")
return false;
else
return true;
}
The method you're calling contains this clause:
// if value changed but didn't validate
if (validateValue != null && !validateValue(backingStore, value))
return false;
This is invoking the validateValue delegate that's passed in. The delegate takes two parameters, both of type T for the generic SetProperty<T>() method, and returns a bool, where false means that the values passed to the delegate don't meet whatever criteria the caller has implemented for the delegate.
Note that backingStore, which is the current value of the property, and value, which is the new value being assigned to the property, are both passed to the validation delegate. So the delegate is free to use either or both as it sees fit.
Your chosen method appears to care only about the newly-assigned value. So you can pass an appropriate delegate either by changing your validation method signature to accept two parameters and ignoring the first one:
private bool ValidateName(string currentName, string newName)
{
if (newName == "default")
return false;
else
return true;
}
and
public string NewGroupName
{
get => _newGroupName;
set => SetProperty(ref _newGroupName, value, validateValue: ValidateName);
}
Or you can leave your method as it is now, and wrap a call to it in a lambda expression:
public string NewGroupName
{
get => _newGroupName;
set => SetProperty(ref _newGroupName, value, validateValue: (_, newName) => ValidateName(newValue));
}
Either one would be fine.
Note the use of the named parameter, since there are additional parameters between the value argument being passed and the delegate reference being passed which you presumably still don't want to specify. Naming the validateValue parameter allows the other parameters to still be omitted, resulting in their default values being passed as expected.
Note also that in either case, a delegate instance is what's actually passed. The C# compiler automatically translates expressions such as a "method group name", as in the first example, or a "lambda expression", as in the second example, into code that instantiates a new delegate instance, using the provided method as the target of the delegate, inferring the delegate type according to the context of the code (in this example, the actual delegate type being passed will be Func<string, string, bool>). Lambda expressions of this form are compiled as "anonymous methods". You can look those terms up for additional information if you like.

How to get class reference from string? [duplicate]

I have a list of types (System.Type) which need te be queried on the database.
For each of this types, I need to call the following extensionmethod (which is part of LinqToNhibernate):
Session.Linq<MyType>()
However I do not have MyType, but I want to use a Type instead.
What I have is:
System.Type typeOne;
But I cannot perform the following:
Session.Linq<typeOne>()
How can I use a Type as a Generic parameter?
You can't, directly. The point of generics is to provide compile-time type safety, where you know the type you're interested in at compile-time, and can work with instances of that type. In your case, you only know the Type so you can't get any compile-time checks that any objects you have are instances of that type.
You'll need to call the method via reflection - something like this:
// Get the generic type definition
MethodInfo method = typeof(Session).GetMethod("Linq",
BindingFlags.Public | BindingFlags.Static);
// Build a method with the specific type argument you're interested in
method = method.MakeGenericMethod(typeOne);
// The "null" is because it's a static method
method.Invoke(null, arguments);
If you need to use this type a lot, you might find it more convenient to write your own generic method which calls whatever other generic methods it needs, and then call your method with reflection.
To do this you need to use reflection:
typeof(Session).GetMethod("Linq").MakeGenericMethod(typeOne).Invoke(null, null);
(assuming that Linq<T>() is a static method on the type Session)
If Session is actually an object, you'll need to know where the Linq method is actually declared, and pass in Session as an argument:
typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
.Invoke(null, new object[] {Session});
I have one general method which call Call Generic Method Through Reflection
/// <summary>
/// This method call your method through Reflection
/// so i wil call the method like CallGenericMethodThroughReflection<Session>(assemblyQualifiedName,Linq,false,new[] { file })
/// </summary>
/// <typeparam name="T">Call method from which file</typeparam>
/// <param name="assemblyQualifiedName">Your can get assemblyQualifiedName like typeof(Payroll.Domain.Attendance.AttendanceApplicationMaster).AssemblyQualifiedName</param>
/// <param name="methodName"></param>
/// <param name="isStaticMethod"></param>
/// <param name="paramaterList"></param>
/// <param name="parameterType">pass parameter type list in case of the given method have overload </param>
/// <returns>return object of calling method</returns>
public static object CallGenericMethodThroughReflection<T>(string assemblyQualifiedName, string methodName,bool isStaticMethod ,object[] paramaterList,Type[] parameterType = null)
{
try
{
object instance = null;
var bindingAttr = BindingFlags.Static | BindingFlags.Public;
if (!isStaticMethod)
{
instance = Activator.CreateInstance<T>();
bindingAttr = BindingFlags.Instance | BindingFlags.Public;
}
MethodInfo MI = null;
var type = Type.GetType(assemblyQualifiedName);
if(parameterType == null)
MI = typeof(T).GetMethod(methodName, bindingAttr);
else
MI = typeof(T).GetMethod(methodName, bindingAttr,null, parameterType, null);//this will work in most case some case not work
if (type == null || MI == null) // if the condition is true it means given method or AssemblyQualifiedName entity not found
return null;
var genericMethod = MI.MakeGenericMethod(new[] { type });
return genericMethod.Invoke(instance, paramaterList);
}
catch (Exception ex)
{
throw ex;
}
}

Avoid using DynamicInvoke() from a Dictionary<Type, Delegate>

I have a sort of message broker class that maps incoming message types to handler methods at runtime. It is important for me to maintain strongly typed messages in the handlers. It works by finding all classes that inherit from IMessage and creating a Delegate to invoke any method that has a Handles(TMessage) attribute on it, where TMessage matches the incoming IMessage underlying Type.
So a "handler" looks like this:
[Handles(typeof(TestMessage))]
public void HandleTestMessage(objectsender, TestMessage request)
{
var response = new TestResponse() { TestInt = request.TestInt };
msgService.Send(sender, response);
}
Again, I'd really like to avoid having an IMessage in the method signature, it's important to me to not have to cast the IMessage in the method body.
The broker class uses the following method to discover and register the handlers:
/// <summary>
/// Subscribes all methods with the <see cref="HandlesAttribute"/> to the given <see cref="IMessage"/> <see cref="Type"/>
/// </summary>
/// <param name="target">The object to inspect</param>
public void SubscribeAll(object target)
{
var targetType = target.GetType();
// Get all private and public methods.
var methods = targetType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
foreach (var method in methods)
{
// If this method doesn't have the Handles attribute then ignore it.
var handlesAttributes = (HandlesAttribute[])method.GetCustomAttributes(typeof(HandlesAttribute), false);
if (handlesAttributes.Length != 1)
continue;
// The method must have only 2 arguments.
var parameters = method.GetParameters();
if (parameters.Length != 2)
{
log.LogDebug(string.Format("Method {0} has too many arguments", method.Name));
continue;
}
// The second argument must be derived from IMessage.
if (!typeof(IMessage).IsAssignableFrom(parameters[1].ParameterType))
{
log.LogDebug(string.Format("Method {0} does not have an IMessage as it's second argument", method.Name));
continue;
}
Type genericDelegate;
if(method.ReturnType == typeof(void))
{
genericDelegate = typeof(Action<,>).MakeGenericType(parameters[0].ParameterType, handlesAttributes[0].MessageType);
}
else
{
genericDelegate = typeof(Func<,,>).MakeGenericType(parameters[0].ParameterType, handlesAttributes[0].MessageType, method.ReturnType);
}
var handler = method.CreateDelegate(genericDelegate, target);
// Success, so register!
Subscribe(
handlesAttributes[0].MessageType,
handler);
}
}
and finally when a message is received, it uses this method to invoke (DynamicInvoke) the handler:
/// <summary>
/// Passes a given <see cref="IMessage"/> and optional sender to any <see cref="Handler"/>s accepting the message's underlying type
/// </summary>
/// <param name="message">The <see cref="IMessage"/> to send</param>
/// <param name="sender">The original sender of the message</param>
private void HandleMessage(IMessage message, object sender = null)
{
var messageType = message.GetType();
if (messageHandlers.TryGetValue(messageType, out List<Delegate> handlers))
{
foreach (var handler in handlers)
{
handler.DynamicInvoke(new object[] { sender, message });
}
}
else
{
log.LogError(string.Format("No handler found for message of type {0}", messageType.FullName));
throw new NoHandlersException();
}
}
I thought I was being smart when I converted the MethodInfos into Delegates (Action<,> or Func<,,>) but I neglected to check the implications of using DynamicInvoke over Invoke. It turns out DynamicInvoke incurs a comparatively large amount of overhead. So my question is, how can I treat the handler Delegates as the actual Delegates that they are (again, Action<,> or Func<,,>)
As you can see, in HandleMessage, I do know the underlying type of message, and sender is always an object. Basically, I need to do something like:
((Action<object, typeof(message)>)handler).Invoke(sender, message);
Obviously that's impossible, but it illustrates what I am trying to accomplish clearly (I think).
I tried creating a sort of in-between generic method:
public void InvokeHandler<TMessage>(Action<object, TMessage> handler, TMessage message, object sender = null)
But I just run into contravariance problems down the line when trying to invoke this method.

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>;

C# reflection, cloning

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;
}

Categories