Let me preface this by saying that I am completely new to reflection.
I have a Dictionary of string to Func<string, string>. I'd like to add a configuration section that would allow me to define the name of static methods that can be programmatically added into this dictionary.
So basically, I'd have something like this:
public static void DoSomething()
{
string MethodName = "Namespace.Class.StaticMethodName";
// Somehow convert MethodName into a Func<string, string> object that can be
// passed into the line below
MyDictionary["blah"] = MethodNameConvertedToAFuncObject;
MyDictionary["foo"] = ANonReflectiveMethod;
foreach(KeyValuePair<string, Func<string, string>> item in MyDictionary)
{
// Calling method, regardless if it was added via reflection, or not
Console.WriteLine(item.Value(blah));
}
}
public static string ANonReflectiveMethod(string AString)
{
return AString;
}
Is it possible to do this, or do I need everything invoked through reflection?
I think all you're looking for is Delegate.CreateDelegate. You'll need to break the name you've got into a class name and a method name. You can then use Type.GetType() to get the type, then Type.GetMethod() to get the MethodInfo, then use:
var func = (Func<string, string>) Delegate.CreateDelegate(
typeof(Func<string, string>), methodInfo);
Once you've created the delegate, you can put it into the dictionary with no problems.
So something like:
static Func<string, string> CreateFunction(string typeAndMethod)
{
// TODO: *Lots* of validation
int lastDot = typeAndMethod.LastIndexOf('.');
string typeName = typeAndMethod.Substring(0, lastDot);
string methodName = typeAndMethod.Substring(lastDot + 1);
Type type = Type.GetType(typeName);
MethodInfo method = type.GetMethod(methodName, new[] { typeof(string) });
return (Func<string, string>) Delegate.CreateDelegate(
typeof(Func<string, string>), method);
}
Note that Type.GetType() will only find types in the currently executing assembly or mscorlib unless you actually specify an assembly-qualified name. Just something to consider. You might want to use Assembly.GetType() instead if you already know the assembly you'll be finding the method in.
Related
Im writing code to transfer data of my ORM entities into a dataset. Because i dont want to write special code for each type defining which properties need to be written down, i am currently using reflection (calling GetProperties on the type of the entities, building up a DataTable for this type and then calling GetValue on each Propertyinfo for each entity). Status quo: It works, but it is slow.
Now i´m trying to build up a method that is returning a function to retrieve the value of certain properties fast, but i am having a hard time here. This is what i got so far:
/// <summary>
/// creates a func that will return the value of the given property
/// </summary>
/// <typeparam name="T">type of the entity</typeparam>
/// <param name="propertyInfo">the property to get the value from</param>
/// <returns>a function accepting an instance of T and returning the value of the property</returns>
private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo)
{
MethodInfo getMethod = propertyInfo.GetGetMethod();
return (Func<T, object>)Delegate.CreateDelegate(typeof(Func<T, object>), getMethod);
}
These are my unit tests:
[TestMethod]
public void TestGenerateDelegate()
{
var employee = new Employee
{
Id = 1,
Name = "TestEmployee",
};
Func<Employee, object> getIdValueFunc = CreateGetPropertyFunc<Employee>(typeof(Employee).GetProperty("Id"));
Assert.AreEqual(1, getIdValueFunc(employee));
}
[TestMethod]
public void TestGenerateDelegateName()
{
var employee = new Employee
{
Name = "Test"
};
Func<Employee, object> getNameValueFunc = CreateGetPropertyFunc<Employee>(typeof(Employee).GetProperty("Name"));
Assert.AreEqual("Test", getNameValueFunc(employee));
}
When i call the first one, an ArgumentException with the message "Exception while binding to the target method" (translated, may be different text) is thrown . The second test passes instead.
I´m pretty sure i´m not correctly handling that CreateDelegate method. Could anyone point me to the right direction, please?
Update:
As PetSerAI statet, it seems to be a problem with the variance, values primitive types cannot be returned as object via CreateDelegate...
You can just invoke your getMethod:
private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo)
{
MethodInfo getMethod = propertyInfo.GetGetMethod();
return o => getMethod.Invoke(o, BindingFlags.Default, null, null, CultureInfo.CurrentCulture);
}
You can use expression trees to dynamically create delegate, which reference specified property:
private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo) {
ParameterExpression p = Expression.Parameter(typeof(T));
return Expression.Lambda<Func<T, object>>(
Expression.Convert(Expression.Property(p, propertyInfo), typeof(object)),
p
).Compile();
}
CreateDelegate(Type, MethodInfo) binds to a static method (you have no static method, which is why you are getting the error)
You can only use Delegate.CreateDelegate for instance methods with this version: CreateDelegate(Type, Object, MethodInfo)
Creates a delegate of the specified type that represents the specified
static or instance method, with the specified first argument.
https://msdn.microsoft.com/en-us/library/system.delegate.createdelegate(v=vs.110).aspx
As per PetSerAl's comment, you should pass 'null' as the 'first argument' to create an "open delegate" into which you would pass the instance.
// In this case, the delegate has one more
// argument than the instance method; this argument comes
// at the beginning, and represents the hidden instance
// argument of the instance method. Use delegate type D1
// with instance method M1.
//
d1 = (D1) Delegate.CreateDelegate(typeof(D1), null, mi1);
// An instance of C must be passed in each time the
// delegate is invoked.
//
d1(c1, "Hello, World!");
Why not go generic all the way and let the compiler create the delegate for you?
public static class Ext
{
public static Func<T, TProp> CreateGetPropertyFunc<T, TProp>(this T obj, Func<T, TProp> func)
{
return func;
}
}
Then:
var getterForId = employee.CreateGetPropertyFunc(x => x.Id);
int result = getterForId(employee);
// result can now be 'int' and doesn't have to be 'object'
If you don't have an actual instance of T upfront, or just don't want an extension-method approach:
public Func<T, object> CreateGetPropertyFunc<T>(Func<T, object> func)
{
return func;
}
Then:
var getterForId = CreateGetPropertyFunc<Employee>(x => x.Id);
object result = getterForId(employee);
// result must be 'object' (unless explicitly casted)
(The former is better in terms of performance because value-types like int will not get boxed, and type safety is preserved)
there is Register function below:
private Dictionary<string, Func<ResolveContainer, object>> _allocFunctionList = ...;
public void Register<T>(Func<ResolveContainer, object> allocFunction)
{
string allocFunctionKey = typeof(T).ToString();
if (_allocFunctionList.ContainsKey(allocFunctionKey))
throw new AllocFunctionKeyExistsException();
_allocFunctionList[allocFunctionKey] = allocFunction;
}
and use case
Register<IFoo>(resolver => new Foo());
Register<IBar>(resolver => new Bar(resolver.Get<IFoo>()));
The Lambda Expression have many kind return type.
So declared return type is object in
Func<ResolveContainer, object>
private Dictionary<string, Func<ResolveContainer, object>> _allocFunctionList = ...;
Question 1
I need to use reflection with the object in the Register Function
but The Register function knows Foo's interface(IFoo) and Func<..., object> -> return type
I want to know Foo and Bar's Type in The Register Function.
how to know Lamda Expression's REAL return class type without update method definition.
Extract real return type in Lambda Expression with any Lib?
or parse Lambda Expression?
i was wondering if it is possible to pass a template into a function like this example:
Dictionary<string, Action<object>> myDict= new Dictionary<string, Action<object>>();
myDict.Add("someString",(nameOfMethod));
this method for example is a setter so it receives as a parameter (double or string or int etc...) and return void.
i suppose the following is impossible..
(i got this ERROR : Error The best overloaded method match for 'System.Collections.Generic.Dictionary>.Add(string, System.Action)' has some invalid arguments)
any ideas how to do it?
this method for example is a setter so it receives as a parameter (double or string or int etc...) and return void.
That's the problem - a method accepting a double isn't applicable for Action<object>, because an Action<object> should be able to be invoked with any object reference as the argument.
You can use a lambda expression to cast and convert though:
myDict.Add("somestring", o => MethodAcceptingDouble((double) o));
You could even write a helper method to do it, although unfortunately due to limitations of type inference you need to specify the type argument explicitly.
static class Test
{
static void Main()
{
var dictionary = new Dictionary<string, Action<object>>();
AddAction<double>(dictionary, "somestring", SampleMethod);
}
static void AddAction<T>(Dictionary<string, Action<object>> dictionary,
string name,
Action<T> action)
{
dictionary.Add(name, arg => action((T) arg));
}
static void SampleMethod(double input)
{
}
}
Let's suppose I have defined Func as follows:
Func<MyClass, object> f = o => o.StringProperty;
or
Func<MyClass, object> f = o => o.Property.SomeMethod();
Is there way to get the actual return type without specifically calling it?
You can get the return type like this:
f.Method.ReturnType
But this will return you the type object. If you want to get Method or String or something that derives from object, you won't be able to have the information unless you call the method.
Actually you could, but this would mean that you'd have to dissassemble the method core and then analyze it to see what the method can return. But even then, there might be many different return types.
So the answer is: if you want to know that it returns an object, then yes you can, otherwise it's not worth the trouble, and it's better to find another way of doing what you need.
Since you are retrieving these Func<MyClass, object> delegates at runtime from other sources, the type information is essentially lost.
Instead, where these functions are defined, you can have the callers essentially encode that type information in a wrapped delegate by taking advantage of the LINQ Expression API (EDIT: Silly me, far more simpler at this point; we already have the generic compile time information):
public class MyClassDelegate
{
private readonly Func<MyClass, object> Function;
public Type ReturnType { get; private set; }
private MyClassDelegate(Func<MyClass, object> function, Type returnType)
{
this.Function = function;
this.ReturnType = returnType;
}
public object Invoke(MyClass context)
{
return Function(context);
}
public static MyClassDelegate Create<TReturnType>(Func<MyClass, TReturnType> function)
{
Func<MyClass, object> nonTypedFunction = o => function(o);
return new MyClassDelegate(nonTypedFunction, typeof(TReturnType));
}
}
(A derived generic MyClassDelegate<TReturnType> : MyClassDelegate class could be made as well to get around some of the sillyness in the Create method, or avoid value-type boxing, or to have the return type information available at compile time or even by reflecting on whatever MyClassDelegate<TReturnType> is.)
Callers defining the delegates instead of working directly with a Func<MyClass, object> would instead work with this class and define their delegates as:
MyClassDelegate f1 = MyClassDelegate.Create(o => o.StringProperty);
MyClassDelegate f2 = MyClassDelegate.Create(o => o.Property.SomeMethod());
Your API would require a MyClassDelegate, with which you can easily access their types:
Console.WriteLine(f1.ReturnType.FullName); //string
Console.WriteLine(f2.ReturnType.FullName); //whatever `SomeMethod()` is declared to return
Finally, you can invoke the delegates or even create Func<MyClass, object> delegates still:
f1.Invoke(myClassInstance);
Func<MyClass, object> f3 = f1.Invoke;
You can do something close to this by using a generic method to make the compiler infer the type arguments:
static Func<T1, R> Infer<T1, R>(Func<T1, R> f) { return f; }
And then:
var func = Infer((string s) => s.Length);
This will encode the return type into the type of func at compilation time.
Of course for a more generally applicable solution you would need a bunch of overloads of Infer to cover Action and Func with one, two, three, etc arguments.
If you then want to get the return type at runtime, for any kind of Func it's as simple as func.Method.ReturnType as ppetrov has already pointed out.
I know there are a few answers on the site on this and i apologize if this is in any way duplicate, but all of the ones I found does not do what I am trying to do.
I am trying to specify method info so I can get the name in a type safe way by not using strings.
So I am trying to extract it with an expression.
Say I want to get the name of a method in this interface:
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}
Currently I can get the name using THIS method:
MemberInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return ((MethodCallExpression)expression.Body).Method;
}
I can call the helper method as follows:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething(null, null));
Console.WriteLine(methodInfo.Name);
But I am looking for the version that I can get the method name without specifying the parameters (null, null)
like this:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething);
But all attempts fail to compile
Is there a way to do this?
x => x.DoSomething
In order to make this compilable I see only two ways:
Go non-generic way and specify it's parameter as Action<string, string>
Specify Action<string, string> as your target delegate type by yourself: GetMethodInfo<IMyInteface>(x => new Action<string,string>(x.DoSomething))
if you are ok to go with second one, which allows you to omit arguments then you can write your GetMethodInfo method as follows:
MemberInfo GetMethodInfo<T>(Expression<Func<T, Delegate>> expression)
{
var unaryExpression = (UnaryExpression) expression.Body;
var methodCallExpression = (MethodCallExpression) unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression) methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo) methodInfoExpression.Value;
return methodInfo;
}
It works for your interface, but probably some generalization will be required to make this working with any method, that's up to you.
The following is compatible with .NET 4.5:
public static string MethodName(LambdaExpression expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodCallObject = (ConstantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)methodCallObject.Value;
return methodInfo.Name;
}
You can use it with expressions like x => x.DoSomething, however it would require some wrapping into generic methods for different types of methods.
Here is a backwards-compatible version:
private static bool IsNET45 = Type.GetType("System.Reflection.ReflectionContext", false) != null;
public static string MethodName(LambdaExpression expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
if (IsNET45)
{
var methodCallObject = (ConstantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)methodCallObject.Value;
return methodInfo.Name;
}
else
{
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo)methodInfoExpression.Value;
return methodInfo.Name;
}
}
Check this sample code on Ideone.
Note, that Ideone does not have .NET 4.5.
The problem with this is that x.DoSomething represents a method group. And you have to somehow explicitly specify what delegate type do you want to convert that method group into, so that the correct member of the group can be selected. And it doesn't matter if that group contains only one member.
The compiler could infer that you mean that one, but it doesn't do that. (I think it's this way so that your code won't break if you add another overload of that method.)
Snowbear's answer contains good advice on possible solutions.
This is a new answer to an old question, but responds to the "verbose" complaint of the accepted answer. It requires more code, but the result is a syntax like:
MemberInfo info = GetActionInfo<IMyInterface, string, string>(x => x.DoSomething);
or, for methods with a return value
MemberInfo info = GetFuncInfo<IMyInterface, object, string, string>(x => x.DoSomethingWithReturn);
where
object DoSomethingWithReturn(string param1, string param2);
Just like the framework provides Action<> and Func<> delegates up to 16 parameters, you have to have GetActionInfo and GetFuncInfo methods that accept up to 16 parameters (or more, although I'd think refactoring is wise if you have methods with 16 parameters). A lot more code, but an improvement in the syntax.
If you are ok with using the nameof() operator you can use the following approach.
One of the benefits is not having to unwrap an expression tree or supply default values or worry about having a non-null instance of the type with the method.
// As extension method
public static string GetMethodName<T>(this T instance, Func<T, string> nameofMethod) where T : class
{
return nameofMethod(instance);
}
// As static method
public static string GetMethodName<T>(Func<T, string> nameofMethod) where T : class
{
return nameofMethod(default);
}
Usage:
public class Car
{
public void Drive() { }
}
var car = new Car();
string methodName1 = car.GetMethodName(c => nameof(c.Drive));
var nullCar = new Car();
string methodName2 = nullCar.GetMethodName(c => nameof(c.Drive));
string methodName3 = GetMethodName<Car>(c => nameof(c.Drive));
If your application would allow a dependency on Moq (or a similar library), you could do something like this:
class Program
{
static void Main(string[] args)
{
var methodName = GetMethodName<IMyInteface>(x => new Action<string,string>(x.DoSomething));
Console.WriteLine(methodName);
}
static string GetMethodName<T>(Func<T, Delegate> func) where T : class
{
// http://code.google.com/p/moq/
var moq = new Mock<T>();
var del = func.Invoke(moq.Object);
return del.Method.Name;
}
}
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}