Sorry for the poor explaination of the problem
Totally rewriting question
I have the following method:
public TReturn FindCached<TSearch, TReturn>(Func<TSearch, TReturn> searchMethod)
where TSearch : ISearchSpecification
where TReturn : class
{
SearchSpecification spec = new GetConcreteSearchSpecification<TSearch>();
//insert magic here to get an attribute from the method on
//the spec class that searchMethod invokes on the line below
return searchMethod(spec);
}
So I have a delegate (searchMethod) and an object (spec) that I want to invoke the delegate on. I want to inspect the object (spec) to find a custom attribute on the method that searchMethod will call when invoked.
Hope this is clearer.
Thanks
Assuming you meant searchMethod to be a variable of type Func<TSearch, TReturn> and mySearchSpec as some implementation of ISearchSpecification<TSearch>, then you are basically asking how to get attributes on a class.
For this, use something like:
object[] attrs = typeof(mySearchSpec).GetCustomAttributes(false);
Assuming that the mySearchSpec type is public, otherwise you may need a different overload for GetCustomAttributes
Addendum:
Based on your revised question, to get the attributes on a method on the actual type of spec used:
Type t = spec.GetType();
MethodInfo m = t.GetMethod("nameOfMethodToBeCalledHere");
object[] attrs = m.GetCustomAttributes(false);
Again, note that you may need overloads for GetMethod or GetCustomAttributes depending on the implementation of the actual class.
Note:
It does seem however like you might be asking for the method called in return searchMethod(spec);, but that is searchMethod and not some method on spec at all.
If you want attributes on searchMethod (nothing to do with spec):
MethodInfo m = searchMethod.Method;
object[] attrs = m.GetCustomAttributes(false);
I think that now covers all permutations of meaning...
This is quite a confusing question, let's see if I have it right:
You have a lambda function (which you describe as a delegate) called searchMethod.
You have a factory-pattern generated object called spec
So you have a method somewhere like this:
[MyCustomAttribute]
public RetClass MyMethod( SearchSpecification input ) {
return input.GetRetClass();
}
And you call this method with:
var result = FindCached( MyMethod );
And in FindCached you want to find MyCustomAttribute - in that case #jerryjvl's answer is right.
Your problem is that you could also do:
var result = FindCached( x => x.GetRetClass() );
I'm not sure from your description whether it's an attribute on the x.GetRetClass() that you actually want. In this case you need to take the lambda apart using expressions, but I wouldn't recommend it - a more complex lambda declaration will result in an anonymous delegate, which is a black-box when you try to parse it at run time.
Instead, as you're using reflection anyway, it might be easier to pass the name of the method that you want instead of the delegate reference:
var result = FindCached( "GetRetClass" );
I ran into a similar situation, jerryjvl's answer explained exactly what I wanted.
I wanted to create a generic profiling method, where I could time how long some method took to run, and retrieve the name of the method using reflection for logging purposes.
The MethodInfo was the key.
Where I have a method like:
public static bool TimeMethod(Func<bool> someMethod)
And then later I want to dynamically get it's name or some attributes off it.
MethodInfo m = someMethod.Method;
object[] attrs = m.GetCustomAttributes(typeof(MonitoringDescriptionAttribute), true);
string name = m.Name;
Cheers
Related
This is very tricky and I'm stuck at the step calling the generic method (MethodInfo) which is returned by another MethodCallExpression (by using MakeGenericMethod) right inside the expression tree context.
Technically the compiled delegate I want looks like this:
Func<IEnumerable, Type, IEnumerable> cast;
So instead of using items.Cast<T>() I can call my compiled delegate like cast(items, typeof(T)).
If using reflection every time calling cast, it would be easy but here I would like to build a compiled delegate based on Expression tree. Here is my code:
public static class EnumerableExtensions {
static readonly Func<IEnumerable, IEnumerable<object>> _enumerableCast = Enumerable.Cast<object>;
static readonly Lazy<MethodInfo> _enumerableCastDefLazy = new Lazy<MethodInfo>(() => _enumerableCast.Method.GetGenericMethodDefinition());
static MethodInfo _enumerableCastDef => _enumerableCastDefLazy.Value;
static Func<Type[], MethodInfo> _makeGenericMethod = _enumerableCastDef.MakeGenericMethod;
static readonly Lazy<Func<IEnumerable, Type, IEnumerable>> _enumerableCompiledCastLazy =
new Lazy<Func<IEnumerable, Type, IEnumerable>>(() => {
var itemsParam = Expression.Parameter(typeof(IEnumerable));
var castTypeParam = Expression.Parameter(typeof(Type));
var castTypeParams = Expression.NewArrayInit(typeof(Type), castTypeParam);
var castMethod = Expression.Call(Expression.Constant(_enumerableCastDef),_makeGenericMethod.Method, castTypeParams);
//here we need to call on castMethod (a static method)
//but the Expression.Call requires a MethodInfo, not an Expression returning MethodInfo
var cast = Expression.Call(..., itemsParam);//<--------- I'm stuck here
return Expression.Lambda<Func<IEnumerable, Type, IEnumerable>>(cast, itemsParam, castTypeParam).Compile();
});
public static Func<IEnumerable, Type, IEnumerable> EnumerableCompiledCast => _enumerableCompiledCastLazy.Value;
public static IEnumerable Cast(this IEnumerable items, Type type){
return EnumerableCompiledCast(items, type);
}
}
So as you can see it's really a dead stuck, never encountered such an issue like this before. I know I can work-around it by invoking the castMethod (as a MethodCallExpression). That way I need to obtain the Invoke method of MethodInfo and use Expression.Call to call that method on the instance castMethod. But wait, if so we still use Method.Invoke as we use Reflection to write code usually without compiling it? I really believe in some hidden magic of Expression.Call which does something different (better and faster) than the MethodInfo.Invoke.
What you're trying to do is completely pointless, and very unlike Enumerable.Cast, which actually does something useful.
Let's take a look at the latter's definition:
IEnumerable<T> Cast<T>(this IEnumerable source);
This takes an untyped IEnumerable and returns a typed IEnumerable<T> based on the generic argument given to the function. You can then use the elements inside the enumerable with the proper type directly, including value types.
Now let's look at your function definition:
IEnumerable Cast(this IEnumerable items, Type type);
This takes an untyped enumerable and returns also an untyped enumerable. What it does inside isn't important, because even if it worked as you want, what you get out of this is still an enumerable of plain objects, so to use these values you still need to cast these things correctly (and unbox the boxed value types). You achieved nothing at all, you already had such a collection -- the thing you passed to your function in the first place.
Even if you make the cast work using a cache of compiled expressions, one per type, which isn't hard to do, the output is still cast back to object by your very return type.
I'm familiar with constructing and calling generic methods through reflection, but for some reason, constructing a generic delegate through reflection is tying my brain in knots!
Perhaps it's because the delegate in particular is not the most simple. This isn't specifically a MongoDb question, but in my case what I'm trying to do is register a class map as a root class where the type is in a type variable because I've only just found it out (not fed in generically).
Ultimately, the method I need to call looks like this:
BsonClassMap.RegisterClassMap<T>(Action<BsonClassMap<T>> classMapInitializer)
So in cases where the class I'm mapping isn't a root class, I don't need to pass the delegate, so the code is pretty straightforward:
MethodInfo method = typeof(BsonClassMap).GetMethod("RegisterClassMap");
MethodInfo genericMethod = method.MakeGenericMethod(entityType);
genericMethod.Invoke(null, null);
I've checked out questions such as How can I dynamically create an Action<T> at runtime? and I understand what's going on there, but for some reason the nested generic in my case is throwing me off and I can't wrap my head around it.
I am trying to construct and invoke the equivalent of this:
BsonClassMap.RegisterClassMap<T>(cm =>
{
cm.AutoMap();
cm.SetIsRootClass(true);
});
Could someone please explain a bit more about generic delegate creation, particularly where the type in the action has a generic type argument of it's own? An example similar to what I'm trying to do would be great!
You should do exactly what the answer in the linked post did.
First, create a generic method that does the thing:
public static void Perform<T>(BsonClassMap<T> cm) {
cm.AutoMap();
cm.SetIsRootClass(true);
}
Then, get the method info of Perform:
var performMethodInfo = typeof(YourType).GetMethod("Perform").MakeGenericMethod(entityType);
Create a Type representing BsonClassMap<T> and create a Type representing Action out of it:
var typeOfBsonClassMap = typeof(BsonClassMap<>).MakeGenericType(entityType);
var typeOfAction = typeof(Action<>).MakeGenericType(typeOfBsonClassMap);
Now use Delegate.CreateDelegate:
var del = Delegate.CreateDelegate(typeOfAction, performMethodInfo);
And then you can pass it into the method:
genericMethod.Invoke(null, new object[] { del });
I have two interfaces
public interface ISerializableDictionary { ... }
public interface ISerializableDictionary<TKey,TValue>
: ISerializableDictionary { ... }
I need to cast from the former to the latter at run time using reflection.
It's clearly easy to interrogate the former with GetType().GetGenericArguments.
But how do I then do the cast? I have this code below but it is failing to compile, for the obvious reason that I am trying to use a variable as a type.
Type[] genericTypes = dictionary.GetType().GenericTypeArguments;
Type keyType = genericTypes[0];
Type valueType = genericTypes[1];
// this compiles but doesn't do the cast
Type dictType = typeof(SerializableDictionary<,>).MakeGenericType(keyType, valueType);
var createdDictionary = Activator.CreateInstance(dictType);
// this is the line that won't compile - 'dictionary' is a SerializableDictionary, and I want to access it through its typed generic interface
ISerializableDictionary<keyType,valueType> serializableDictionary = dictionary as ISerializableDictionary<keyType, valueType>;
The more specified interface has a method which I need to call. The less specified interface does not (and can't ever be, because the call needs a typed argument).
Is the solution something to do with dictionary.GetType().GetInterfaces()?
Any steer will be wildly appreciated. Programming solo at the moment so I don't have a team to call on, hence the query here.
UPDATE - in response to comments
The problem I am trying to solve is how to serialize members of an object where the members are themselves enumerable. I am trying to figure out how serialization libraries do it as a learning exercise and because I have a few ideas that I want to explore. Serialization & Reflection are not my main areas of programming so I am stumbling to learn them.
So I have (as reduced code):
public class ExperimentalSerializer<T>
{
public void Serialize(T objectToSerialize)
{
IEnumerable<object> collectionsToSerializeToCSV = objectToSerialize.GetEnumerableMembers();
foreach (object collectionToSerialize in collectionsToSerializeToCSV)
{
string csvString = "";
if (collectionToSerialize.IsDictionary())
{
// serialize dictionary here to csvString
// but cannot properly access contents through just IDictionary
// need IDictionary<TKey,TValue>
// ** ALSO SEE TEXT BELOW THIS CODE SNIPPET**
}
else if (collectionToSerialize.IsList())
{
// serialize list here to csvString
}
else if (collectionToSerialize.GetType().IsArray)
{
// serialize array here to csvString
}
// save csvString to somewhere useful here
}
}
}
And elsewhere I have an extension method:
public static IEnumerable<object> GetEnumerableMembers(this object objectToInterrogate)
{
Type objectType = objectToInterrogate.GetType();
// get the enumerable properties
PropertyInfo[] properties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
IEnumerable<PropertyInfo> enumerableProperties = properties.Where(propertInfo => propertInfo.PropertyType.GetInterfaces().Any(x => x == typeof(IEnumerable)));
IEnumerable<PropertyInfo> serializableProperties = enumerableProperties.Where(p => p.IsSerializable());
IEnumerable<object> enumerablePropertyValues = serializableProperties.Select(p => p.GetValue(objectToInterrogate, null));
// get the enumerable fields
FieldInfo[] fields = objectType.GetFields(BindingFlags.Instance | BindingFlags.Public);
IEnumerable<FieldInfo> enumerablefields = fields.Where(propertInfo => propertInfo.FieldType.GetInterfaces().Any(x => x == typeof(IEnumerable)));
IEnumerable<object> enumerablefieldValues = enumerablefields.Select(f => f.GetValue(objectToInterrogate));
// merge the two lists together
IEnumerable<object> enumerableMembers = enumerablePropertyValues.Union(enumerablefieldValues);
return enumerableMembers.ToList();
}
One specific challenge I am investigating is how to serialize an enumerable (Dictionary, List or array TValue[]) where TValue is itself a complex type (e.g. a class that can be serialized). This cannot be ascertained without knowing the type of TValue, but this cannot be retrieved from IDictionary or IList alone and these can only be enumerated with the type object.
This is the very specific point I am trying to investigate and potentially to control: how to determine TValue and then to work out if/how to serialize it in turn. My idea is to cast to more-specified generics with known type parameters but I get a bit lost at this point.
Hope this helps.
#SLaks points out in the comments:
Casting is inherently a compile-time operation. Casting to a type only known at runtime makes no sense. You can't call your method if its types are not known at compile-time.
That's absolutely right. You can, of course, still call the intended method at runtime, but you'll need to use (more) reflection to do it, since you have no way to get the compiler to generate a statically-typed call.
To do this, take the Type object you already constructed using MakeGenericType(), and call GetMethod() on it to get the Type.MethodInfo object corresponding to the method to call. Then, call MethodInfo.Invoke().
Type dictType = typeof(SerializableDictionary<,>).MakeGenericType(keyType, valueType);
MethodInfo method = dictType.GetMethod("MyMethod");
object returnValue = method.Invoke(dictionary, new object[] { /* arguments */ });
TMI...
When you write dictionary.MyMethod(), the C# compiler generates a Callvirt IL (byte code) instruction. The object to call the method on (and the arguments to the method) are pushed onto the stack, and the argument to Callvirt is the metadata token corresponding to the type-qualified ISerializableDictionary<TKey,TValue>.MyMethod method. This is the normal calling mechanism in .NET. When you (and the compiler) don't know what TKey and TValue are at compile time, there's no way to get the right metadata token for the method, and no way to generate the Callvirt. That's why you have to use the reflection API.
You can, however, use something like DynamicMethod to generate your own IL and JIT it at runtime. Once JITted, the call is just as fast as one statically generated by the compiler. There is of course significant overhead to generating a dynamic method, but it's a one-time overhead.
Of course, #DavidL points out:
The approach here seems wildly off-course. Instead of asking for a specific solution, can you please describe the specific concrete problem that you are trying to solve?
That, too, is absolutely right. So don't do what I just suggested unless you really, really know what you're doing and have a really, really good reason. (Hint: You don't.) But I thought this information might give you a better overall picture of why you can't do what you expected to do.
I have a class with an IList readonly property. I have created a simple extension method, AddCSV, to add multiple items to that list. I want to create an action delegate to populate the list via the extension method. So far, I have
private Action<TListPropertyContainer, TDataValue> CreateListPropertySetter<TListPropertyContainer, TDataValue>(string listName)
{
var list = typeof(TListPropertyContainer).GetProperty(listName);
var method = typeof(Extensions).GetMethod("AddCSV");
return (Action<TListPropertyContainer, TDataValue>)Delegate.CreateDelegate(typeof(Action<TListPropertyContainer, TDataValue>), list, method);
}
but obviously this isn't working!
I am aware that there are other options. For example
a) I could inherit the list into my own customer class and add the AddCSV there
b) I could make items property read/write and set a fully populated list into my class
I'd be grateful if someone could correct me.
Many thx
Simon
There are two main problems.
You are trying to invoke the method on a PropertyInfo, not a list. To get the value of the property you would need to make a call to GetValue()
The call to GetMethod() doesn't specify binding flags. I suspect it might work better with GetMethod("AddCSV", BindingFlags.Public | BindingFlags.Static).
That being said, why are you instantiating it reflectively when you know the type and the method beforehand? It seems like you could just do:
private Action<TListPropertyContainer, TDataValue> CreateListPropertySetter<TListPropertyContainer, TDataValue>(string listName)
{
var propertyInfo = typeof(TListPropertyContainer).GetProperty(listName);
return (container,value) => {
var list = (IList<TDataValue>)propertyInfo.GetValue(container,null);
list.AddCSV(list);
};
}
If I am making incorrect assumptions about the signature of the extension method or the type of property, you can still do it with Delegate.CreateDelegate(), but take the comments about the PropertyInfo and the BindingFlags into account
You're trying to use list as the target of the delegate - but list is of type PropertyInfo, which sounds like it's not what you were expecting. Assuming you want to get the value of the property, and then call the method on that, you'll need to pass in the object containing the property as well, so you can get the actual list. (Alternatively, maybe it's "this" - you haven't really made that clear.) Either way, you can get the list itself and use that as the target. For example:
private Action<TListPropertyContainer, TDataValue>
CreateListPropertySetter<TListPropertyContainer, TDataValue>
(string listName, object target)
{
var listProperty = typeof(TListPropertyContainer).GetProperty(listName);
object list = listProperty.GetValue(target, null);
var method = typeof(Extensions).GetMethod("AddCSV");
return (Action<TListPropertyContainer, TDataValue>)Delegate.CreateDelegate(
typeof(Action<TListPropertyContainer, TDataValue>), list, method);
}
If this doesn't help, please edit your question with a short but complete console app demonstrating the problem. Right now there are too many unknowns to definitely help you.
This is a theoretical question, I've already got a solution to my problem that took me down a different path, but I think the question is still potentially interesting.
Can I pass object properties as delegates in the same way I can with methods? For instance:
Let's say I've got a data reader loaded up with data, and each field's value needs to be passed into properties of differing types having been checked for DBNull. If attempting to get a single field, I might write something like:
if(!rdr["field1"].Equals(DBNull.Value)) myClass.Property1 = rdr["field1"];
But if I've got say 100 fields, that becomes unwieldy very quickly. There's a couple of ways that a call to do this might look nice:
myClass.Property = GetDefaultOrValue<string>(rdr["field1"]); //Which incidentally is the route I took
Which might also look nice as an extension method:
myClass.Property = rdr["field1"].GetDefaultOrValue<string>();
Or:
SetPropertyFromDbValue<string>(myClass.Property1, rdr["field1"]); //Which is the one that I'm interested in on this theoretical level
In the second instance, the property would need to be passed as a delegate in order to set it.
So the question is in two parts:
Is this possible?
What would that look like?
[As this is only theoretical, answers in VB or C# are equally acceptable to me]
Edit: There's some slick answers here. Thanks all.
I like using expression trees to solve this problem. Whenever you have a method where you want to take a "property delegate", use the parameter type Expression<Func<T, TPropertyType>>. For example:
public void SetPropertyFromDbValue<T, TProperty>(
T obj,
Expression<Func<T, TProperty>> expression,
TProperty value
)
{
MemberExpression member = (MemberExpression)expression.Body;
PropertyInfo property = (PropertyInfo)member.Member;
property.SetValue(obj, value, null);
}
Nice thing about this is that the syntax looks the same for gets as well.
public TProperty GetPropertyFromDbValue<T, TProperty>(
T obj,
Expression<Func<T, TProperty>> expression
)
{
MemberExpression member = (MemberExpression)expression.Body;
PropertyInfo property = (PropertyInfo)member.Member;
return (TProperty)property.GetValue(obj, null);
}
Or, if you're feeling lazy:
public TProperty GetPropertyFromDbValue<T, TProperty>(
T obj,
Expression<Func<T, TProperty>> expression
)
{
return expression.Compile()(obj);
}
Invocation would look like:
SetPropertyFromDbValue(myClass, o => o.Property1, reader["field1"]);
GetPropertyFromDbValue(myClass, o => o.Property1);
(Adding a second answer because it's on a completely different approach)
To address your original problem, which is more about wanting a nice API for mapping named values in a datareader to properties on your object, consider System.ComponentModel.TypeDescriptor - an often overlooked alternative to doing reflective dirtywork yourself.
Here's a useful snippet:
var properties = TypeDescriptor.GetProperties(myObject)
.Cast<PropertyDescriptor>()
.ToDictionary(pr => pr.Name);
That creates a dictionary of the propertydescriptors of your object.
Now I can do this:
properties["Property1"].SetValue(myObject, rdr["item1"]);
PropertyDescriptor's SetValue method (unlike System.Reflection.PropertyInfo's equivalent) will do type conversion for you - parse strings as ints, and so on.
What's useful about this is one can imagine an attribute-driven approach to iterating through that properties collection (PropertyDescriptor has an Attributes property to allow you to get any custom attributes that were added to the property) figuring out which value in the datareader to use; or having a method that receives a dictionary of propertyname - columnname mappings which iterates through and performs all those sets for you.
I suspect an approach like this may give you the API shortcut you need in a way that lambda-expression reflective trickery - in this case - won't.
Ignoring whether this is useful in your specific circumstances (where I think the approach you've taken works just fine), your question is 'is there a way to convert a property into a delegate'.
Well, there kind of might be.
Every property actually (behind the scenes) consists of one or two methods - a set method and/or a get method. And you can - if you can get a hold of those methods - make delegates that wrap them.
For instance, once you've got hold of a System.Reflection.PropertyInfo object representing a property of type TProp on an object of type TObj, we can create an Action<TObj,TProp> (that is, a delegate that takes an object on which to set the property and a value to set it to) that wraps that setter method as follows:
Delegate.CreateDelegate(typeof (Action<TObj, TProp>), propertyInfo.GetSetMethod())
Or we can create an Action<TProp> that wraps the setter on a specific instance of TObj like this:
Delegate.CreateDelegate(typeof (Action<TProp>), instance, propertyInfo.GetSetMethod())
We can wrap that little lot up using a static reflection extension method:
public static Action<T> GetPropertySetter<TObject, T>(this TObject instance, Expression<Func<TObject, T>> propAccessExpression)
{
var memberExpression = propAccessExpression.Body as MemberExpression;
if (memberExpression == null) throw new ArgumentException("Lambda must be a simple property access", "propAccessExpression");
var accessedMember = memberExpression.Member as PropertyInfo;
if (accessedMember == null) throw new ArgumentException("Lambda must be a simple property access", "propAccessExpression");
var setter = accessedMember.GetSetMethod();
return (Action<T>) Delegate.CreateDelegate(typeof(Action<T>), instance, setter);
}
and now I can get a hold of a 'setter' delegate for a property on an object like this:
MyClass myObject = new MyClass();
Action<string> setter = myObject.GetPropertySetter(o => o.Property1);
That's strongly typed, based on the type of the property itself, so it's robust in the face of refactoring and compile-time typechecked.
Of course, in your case, you want to be able to set your property using a possibly-null object, so a strongly typed wrapper around the setter isn't the whole solution - but it does give you something to pass to your SetPropertyFromDbValue method.
No, there's nothing akin to method group conversions for properties. The best you can do is to use a lambda expression to form a Func<string> (for a getter) or an Action<string> (for a setter):
SetPropertyFromDbValue<string>(value => myClass.Property1 = value,
rdr["field1"]);
Worth mentioning you can do this with some reflection trickery..
something like...
public static void LoadFromReader<T>(this object source, SqlDataReader reader, string propertyName, string fieldName)
{
//Should check for nulls..
Type t = source.GetType();
PropertyInfo pi = t.GetProperty(propertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
object val = reader[fieldName];
if (val == DBNull.Value)
{
val = default(T);
}
//Try to change to same type as property...
val = Convert.ChangeType(val, pi.PropertyType);
pi.SetValue(source, val, null);
}
then
myClass.LoadFromReader<string>(reader,"Property1","field1");
As others have pointed, static reflexion is the way to go.
Those classes work out of the box :
http://www.codeproject.com/Articles/36262/Getting-Fun-with-Net-Static-Reflection.aspx