Creating functions to retrieve values of properties retrieved via reflection - c#

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)

Related

How to groupBy with compiled lambda function with type generated during runtime

I have a compiledLambda function that runs against an interface. Unfortunately the interface is just a marker interface and the real type is generated on the fly during runtime and has properties I want to do a grouping on.
Here's some sample code:
class Program
{
static void Main(string[] args)
{
// Just an example assignment: In the real life scenario the dynamic generated class is created during runtime.
IEnumerable<IDynamicGeneratedModelClass> list = GetDataFromService();
// get the 'real' type from the list
LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(list.First().GetType(), typeof(object), "SomeProperty");
Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpression.Compile();
// Expected result: Group list on "SomeProp"
var result = list.GroupBy(compiledLambdaFunction);
}
private static IList<IDynamicGeneratedModelClass> GetDataFromService()
{
return new List<IDynamicGeneratedModelClass> {
new DynamicGeneratedModelClass("Class1"),
new DynamicGeneratedModelClass("Class2")
};
}
}
public interface IDynamicGeneratedModelClass
{}
public class DynamicGeneratedModelClass : IDynamicGeneratedModelClass
{
public DynamicGeneratedModelClass(string someProperty)
{
SomeProperty = someProperty;
}
public string SomeProperty { get; }
}
When the the lambda expression is compiled it throws the following exception:
System.InvalidCastException: 'Unable to cast object of type
'System.Func`2[ConsoleApp12.DynamicGeneratedModelClass,System.Object]'
to type
'System.Func`2[ConsoleApp12.IDynamicGeneratedModelClass,System.Object]'.'
Could you please give me a hint what I am doing wrong and how to fix it ?
The first generic parameter of the Func<T, TResult> delegate is declared as contravariant (in), which means that you can assign delegate with less derived parameter to delegate with more derived parameter, but not vice versa (in another words, you can cast Func<IDynamicGeneratedModelClass,Object> to Func<DynamicGeneratedModelClass,Object>, but cannot cast Func<DynamicGeneratedModelClass,Object> to Func<IDynamicGeneratedModelClass,Object>).
To avoid this problem, instead of lambda expression you generate now:
// lambda has "wrong" type Func<DynamicGeneratedModelClass, object>
(DynamicGeneratedModelClass item) => item.SomeProperty
generate lambda equivalent to this:
// lambda now has "correct" type Func<IDynamicGeneratedModelClass, object>
(IDynamicGeneratedModelClass item) => ((DynamicGeneratedModelClass)item).SomeProperty
I'm not familiar with the DynamicExpression library you used to generate you lambda, but this can be easily done using just System.Linq.Expression classes:
var itemType = list.First().GetType();
var propertyName = "SomeProperty";
var parameterExpr = Expression.Parameter(typeof(IDynamicGeneratedModelClass));
var castExpr = Expression.Convert(parameterExpr, itemType);
var propExpr = Expression.Property(castExpr, propertyName);
var lambdaExpr = Expression.Lambda(propExpr, parameterExpr);
// Compiled lambda is now of type Func<IDynamicGeneratedModelClass, object>
Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpr.Compile();
var result = list.GroupBy(compiledLambdaFunction);

Confusion over a Func<> predicate expression

I have read about Func<>, which says it iss a delegate and you can use it like for example:
Func<class,bool>
means you send a class or anything and get a bool result, this is what I got!
but what does the following mean?
Func<Class, bool> predicate
I have no idea, can you make it clear for me?
The former will not compile since class is a registered keyword and can only be used for class definitions.
The latter is a Func<T, TResult> which is a function that takes a parameter of type T and returns an object of type TResult. So in your case, the function takes an object of type Class and returns a bool.
The naming of Class is unfortunate but it’s actually allowed to use that identifier for a type. The following would be an example that takes such an object of type Class and then checks a property of it, returning true or false depending on the success of the comparison.
Func<Class,bool> predicate = obj => obj.Prop == "Foo";
var x = new Class();
x.Prop = "Foo";
Console.WriteLine(predicate(x)); // true
// with the following class definition
public class Class
{
public string Prop { get; set; }
}
A Func<> object is callable, just like methods, so we can use parentheses to call it and pass the object here. This would be equivalent to a method like this:
public bool predicate(Class obj)
{
return obj.Prop == "Foo";
}
But the usual way to use Func<> is using lambda expressions to be able to create functions quickly inline. This is very commonly used in LINQ where you use lambda expressions, and as such Func<> objects, all the time:
var filtered = listOfOjects.Where(obj => obj.Prop == "Foo").ToList();
// ^^^^^^^^^^^^^^^^^^^^^^^^
// this is the predicate function from above
// so you could also pass the predicate Func from above:
var filtered = listOfObjects.Where(predicate).ToList()
Func<MyClass,bool> is a delegate type
In Func<MyClass, bool> predicate , predicate is a delegate variable.
You would normally see something like
Func<MyClass, bool> predicate = c => c.IsValid;
...
if (predicate(myClass1)) DoSomething();
That's just how you instantiate the Func. Compare to a string:
string str;
If you want to instantiate and assign it at the same time, you do something like this:
Func<string, bool> isLongerThanThree = input => input.Length > 3;
isLongerThanThree("string"); // Returns "true"
Are you referring to the word predicate?
That's just the name of a parameter. Notice the similarity:
MyMethod(int myAge)
MyMethod(List<bool> myBooleans)
MyMethod(Func<Class,bool> myPredicate)
Also notice the similarities between:
int myAge = 30;
myAge is a variable of type int who has been given the value of 30.
Func<Class,bool> myPredicate = (x => x.IsAlive);
myPredicate is a variable of type Func<Class,bool> who has been given the value of (x => x.IsAlive).
Func<> is a delegate which represents a method which return a result. C# provides signatures for up to 15 input arguments, which should be enough to represent all possible methods you will ever need :)
it is hardly event to imagine method which has 15 input arguments. Beside Func<> there are also some special version of the delegate like Predicate<T> which is nothing else that Func<in T, bool TResult> or Action<> which represent a function without return value, return value is void.
Delegates(C# Programming Guide)
You can assign any method, static or instance or even anonymous with the matching signature to the Func<>. For example:
Func<MyClass, bool> predicate = (myClass) => {return true;} //anonymoys method
public class MyClass
{
public bool MyPredicate(MyClass myClass)
{
return true;
}
public static bool MyStaticPredicate(MyClass myClass)
{
return true;
}
}
Func<MyClass, bool> predicate = new MyClass().MyPredicate;
Func<MyClass, bool> staticPredicate = MyClass.MyStaticPredicate;

How to register lambda expression into Func<>

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?

Mixing Reflection with Standard Calls

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.

Get "Object" return type from Func<MyClass, object>

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.

Categories