I want to be able to do the equivalent to the following at runtime:
var action = new Action<ANYTHING AT RUNTIME>(obj => Console.WriteLine("Called = " + obj));
I know I need to get the correct type for the Action, but not sure how to get the final bit using Delegate.Create. Type represent T in the Action definition.
var actionType = typeof(Action<>).MakeGenericType(Type);
var constructor = actionType.GetConstructors()[0];
var #delegate = Delegate.CreateDelegate(actionType, <WHAT GOES HERE>);
the point people seem to be missing is I'm trying to create an instance of Action where T can not be specified statically because it is being used from a class derived from Attribute - this means T could be anything and it can not be defines as a generic definition
Cheers
If you know what the operation you need to perform is and how to perform it regardless of type (as in your example) why not just make a generic method that performs the operation and create your delegate that way?
class Program
{
public static void Perform<T>(T value)
{
Console.WriteLine("Called = " + value);
}
public static Delegate CreateAction(Type type)
{
var methodInfo = typeof (Program).GetMethod("Perform").MakeGenericMethod(type);
var actionT = typeof (Action<>).MakeGenericType(type);
return Delegate.CreateDelegate(actionT, methodInfo);
}
static void Main(string[] args)
{
CreateAction(typeof (int)).DynamicInvoke(5);
Console.ReadLine();
}
}
Create a generic method to produce an Action with the desired generic parameter:
private Action<T> CreateAction<T>() =>
new Action<T>(obj => Console.WriteLine("Called = " + (object)obj));
Call it like this:
var action = GetType()
.GetMethod(nameof(CreateAction), BindingFlags.NonPublic | BindingFlags.Instance)
?.MakeGenericMethod(type)
?.Invoke(this, new object[]{});
You can use following code, it works if type can be casted to an object:
Action<object> func = o => Console.WriteLine("Called = " + o.GetType().Name);
var actionType = typeof(Action<>).MakeGenericType(type);
var constructor = actionType.GetConstructors()[0];
var #delegate = Delegate.CreateDelegate(actionType, func.Method);
However if type is enum or other value type it won't work.
Thanks to "#prashanth" suggestion, I managed to dynamically create and call an Action<> with a runtime type thanks to the dynamic keyword :
public Action<dynamic> GetDynamicAction(/* some params */)
{
return oDyn =>
{
//here is the action code with the use of /* some params */
};
}
Example with a basic action handler :
public class ActionHandler
{
public ReturnType DoAction<T>(Action<T> t)
{
//whatever needed
}
}
Use case :
/* some params */ = Any runtime type specific data (in my case I had a Type and a MethodInfo passed as parameters and that were called in the action)
var genericMethod = actionHandler.GetType().GetMethod(nameof(ActionHandler.DoAction));
var method = genericMethod.MakeGenericMethod(runtimeGenericType);
var actionResult = (ReturnType) method.Invoke(actionHandler, new object[]
{
GetDynamicAction(/*some params*/)
}
);
Use the following code to create a delegate, which is late bound in the type parameter. See also How to: Examine and Instantiate Generic Types with Reflection.
abstract class ActionHelper {
protected abstract Delegate CreateActionImpl();
// A subclass with a static type parameter
private class ActionHelper<T> : ActionHelper {
protected override Delegate CreateActionImpl() {
// create an Action<T> and downcast
return new Action<T>(obj => Console.WriteLine("Called = " + (object)obj));
}
}
public static Delegate CreateAction(Type type) {
// create the type-specific type of the helper
var helperType = typeof(ActionHelper<>).MakeGenericType(type);
// create an instance of the helper
// and upcast to base class
var helper = (ActionHelper)Activator.CreateInstance(helperType);
// call base method
return helper.CreateActionImpl();
}
}
// Usage
// Note: The "var" is always "Delegate"
var #delegate = ActionHelper.CreateAction(anyTypeAtRuntime);
That said, I don't recommend using this method. Instead, use
Action<object> action = obj => Console.WriteLine("Called = " + obj);
It offers
The same functionality.
Your original code "Called = " + obj" calls .ToString() on the parameter. So does the above.
No performance difference.
If the obj parameter is a value type, both variants perform a boxing operation. The boxing in the first is not obvious, but "Called = " + obj" boxes value types.
Shorter and less error-prone.
The short answer is to create a delegate MyActionDelegate and then use:
delegate void MyActionDelegate(T arg);
Delegate #delegate = new MyActionDelegate((a) => Console.WriteLine(a));
Here's a working example using a generic class:
public class MyClass<T>
{
public delegate void ActionDelegate(T arg);
public void RunGenericAction(T arg)
{
var actionType = typeof(Action<>).MakeGenericType(typeof(T));
var constructor = actionType.GetConstructors()[0];
Delegate #delegate = new ActionDelegate((a) => { Console.WriteLine(arg); });
var inst = (Action<T>)constructor.Invoke(new object[] {
#delegate.Target,
#delegate.Method.MethodHandle.GetFunctionPointer()
});
inst(arg);
}
}
Use it like this, which outputs 123 to the console:
var c = new MyClass<int>();
c.RunGenericAction(123);
You'll notice I'm passing two parameters to Constructor.Invoke; that's because it turns out that a delegate argument actually compiles as two arguments: the target object of the function, and a pointer to the function. I can't take credit for the fancy footwork there; "borrowed" info from this excellent answer on how to pass a delegate argument using reflection.
Related
I have few classes deriving from abstract class A - A1, A2, A3, etc.
I need to register these classes to BsonClassMap using their own discriminators using code like this:
BsonClassMap.RegisterClassMap<A1>(cm =>
{
cm.AutoMap();
cm.SetDiscriminator(discriminator)
});
Since I will have more of such classes in future, I want to use reflection to do that:
foreach (var type in Assembly.GetAssembly(typeof(A))
.GetTypes().Where(t => t.IsClass
&& !t.IsAbstract
&& t.IsSubclassOf(typeof(A))))
{
var discriminator = type.GetField("Discriminator")
.GetRawConstantValue()
.ToString();
var method = typeof(BsonClassMap).GetMethods()
.FirstOrDefault(m => m.IsGenericMethod
&& m.Name == "RegisterClassMap");
if (method == null) continue;
var generic = method.MakeGenericMethod(type);
generic.Invoke(this, null);
}
How can I pass such lambda expression to this function?
cm =>
{
cm.AutoMap();
cm.SetDiscriminator(discriminator)
});
I have found many descriptions of how to call generic methods, but can't get this to work.
In addition to the answer posted by #aL3891, I mocked up a simple example of how I would call this like so:
In this situation, SampleClass is the standin for BsonClassMap, and AbstractClass stands in for A, etc
class Program
{
static void Main(string[] args)
{
SampleClass.Foo<int>(param =>
{
});
var discoveredTypes = new List<Type>
{
typeof(DerivedOne),
typeof(DerivedTwo),
typeof(DerivedThree)
};
foreach (var type in discoveredTypes)
{
var methodType = typeof(Program).GetMethods().FirstOrDefault(x => x.Name == "CreateMethod").MakeGenericMethod(type);
var method = methodType.Invoke(null, null);
var staticMethod = typeof(SampleClass).GetMethods().FirstOrDefault(x => x.Name == "Foo").MakeGenericMethod(type);
staticMethod.Invoke(null, new object[] { method });
}
Console.ReadKey();
}
public static Action<T> CreateMethod<T>()
{
return new Action<T>((param) =>
{
Console.WriteLine("This is being invoked with type: " + typeof(T).Name);
});
}
}
public abstract class AbstractClass { }
public class DerivedOne : AbstractClass { }
public class DerivedTwo : AbstractClass { }
public class DerivedThree : AbstractClass { }
public class SampleClass
{
public static void Foo<TGenericType>(Action<TGenericType> setupMethod)
where TGenericType : new()
{
TGenericType instance = new TGenericType();
setupMethod(instance);
}
}
The problem is that you're trying to go from a runtime declaration to a compile time generic, so it's easy enough to just make a factory style method you can invoke generically to construct the delegate for you. The CreateMethod method in Program would be involved in making your lambda expression, and then you could invoke the static method on BsonClassMap that way.
There are two parts to this question,
To pass a lambda to this method you simply pass it in an array as the second argument to the Invoke call. generic.Invoke(this, new object[]{foo});
However, the problem now is how do you get a object containing a lambda?
This doesn't work var l = () => {...}, so whats the deal?
Well lambdas in c# can have two different types. They can be a a delegate (Func<...>or Action<..> or they can be an expression Expression<Func<...>>
What it actually ends up being depends on what you assign it to, or rather what the compiler infers it to be. So what you have to write to get an expression is Expression<Func<int>> e = () => 3;
Now you can pass e into your invoke call (provided that the expression types match up of course)
If this code is entirely generic, one solution might be to have a helper method that actually returns the expression you pass in:
public Action<T> GetMyDelegate<T>() where T: A{
return (T cm) => {
cm.AutoMap();
cm.SetDiscriminator(discriminator)
};
}
Also note that you can initialize a delegate such as Action with a method name:
public void Method1() {
var a = new Action(Method2);
}
public void Method2()
{ }
You can also create a delegate from a MethodInfo, say if different subtypes of A have their own init method that you find with reflection:
http://msdn.microsoft.com/en-us/library/53cz7sc6.aspx
Assume I have a class like so:
public class MyClass<T>
{
public void Foo(T t)
{
}
}
Now, assume, I have an instance of MyClass<int> and a MethodInfo of its Foo method.
Calling methodInfo.GetParameters() will return a ParameterInfo array with one entry, referring to type int. My problem is, that I can't seem to find out, if that parameter was declared as int in the class or as T.
What am I trying to achieve?
At runtime, I want to read the documentation of the method specified by MethodInfo from the XML Doc file generated by Visual Studio.
For the above defined method, the key looks like this:
<namespace>.MyClass`1.Foo(`0)
The `0 refers to the first generic type parameter of the declaring class. To be able to construct this string, I need to somehow get this information.
But how? MethodInfo doesn't seem to contain that info...
The key seems to be Type.ContainsGenericParameters on the parameter type:
Given
public class MyClass<T>
{
public void Foo(T t)
{
}
public void Bar(int i)
{
}
}
Then
class Program
{
static void Main(string[] args)
{
var obj = new MyClass<int>();
// Closed type
var closedType = obj.GetType();
// Open generic (typeof(MyClass<>))
var openType = closedType.GetGenericTypeDefinition();
// Methods on open type
var fooT = openType.GetMethod("Foo");
var barint = openType.GetMethod("Bar");
// Parameter types
var tInFoo = fooT.GetParameters()[0].ParameterType;
var iInBar = barint.GetParameters()[0].ParameterType;
// Are they generic?
var tInFooIsGeneric = tInFoo.ContainsGenericParameters;
var iInBarIsGeneric = iInBar.ContainsGenericParameters;
Console.WriteLine(tInFooIsGeneric);
Console.WriteLine(iInBarIsGeneric);
Console.ReadKey();
}
}
outputs
True
False
This will obviously need more work for overloads and so on.
Could you get the definition of the generic class through Type.GetGenericTypeDefinition Method and find there the definition for the same method, say, by name (and the signature), and then compare Foo(T t) and Foo(int t):
MyClass<int> c = new MyClass<int>();
Type concreteType = c.GetType();
Console.Write("Concrete type name:");
Console.WriteLine(concreteType.FullName);
Console.WriteLine();
MethodInfo concreteMethod = concreteType.GetMethod("Foo");
if (concreteMethod != null)
{
Console.WriteLine(concreteMethod.Name);
foreach (ParameterInfo pinfo in concreteMethod.GetParameters())
{
Console.WriteLine(pinfo.Name);
Console.WriteLine(pinfo.ParameterType);
Console.WriteLine();
}
Console.WriteLine();
}
if (concreteType.IsGenericType)
{
Console.Write("Generic type name:");
Type genericType = concreteType.GetGenericTypeDefinition();
Console.WriteLine(genericType.FullName);
Console.WriteLine();
MethodInfo genericMethod = genericType.GetMethod("Foo");
if (genericMethod != null)
{
Console.WriteLine(genericMethod.Name);
foreach (ParameterInfo pinfo in genericMethod.GetParameters())
{
Console.WriteLine(pinfo.Name);
Console.WriteLine(pinfo.ParameterType);
Console.WriteLine();
}
Console.WriteLine();
}
}
I don't know if you have considered using Mono.Cecil instead of .Net's reflection.
// Gets the AssemblyDefinition (similar to .Net's Assembly).
Type testType = typeof(MyClass<>);
AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(new Uri(testType.Assembly.CodeBase).LocalPath);
// Gets the TypeDefinition (similar to .Net's Type).
TypeDefinition classDef = assemblyDef.MainModule.Types.Single(typeDef => typeDef.Name == testType.Name);
// Gets the MethodDefinition (similar to .Net's MethodInfo).
MethodDefinition myMethodDef = classDef.Methods.Single(methDef => methDef.Name == "Foo");
then myMethodDef.FullName returns
"System.Void MyNamespace.MyClass`1::Foo(System.Int32,T,System.String)"
and classDef.GenericParameters[0].FullName returns
"T"
Note that Mono.Cecil uses a different way of writing generics, nested classes and arrays:
List[T] => List<T>
MyClass+MyNestedClass => MyClass/MyNestedClass
int[,] => int[0...,0...]
This was a tricky one. If you have a MethodInfo instance of a (non-generic) method, which was obtained on an open generic Type, you can actually use it to repeatedly close the method (i.e., with different generic arguments for the enclosing type).
The key is to use the obscure static function MethodInfo.GetMethodFromHandle(...):
Complete working example:
static class MyType<T>
{
public static int TheMethod() => typeof(T).MetadataToken; // demo method
};
How to use:
static void demo()
{
var Topen = typeof(MyType<>);
var mi_open = Topen.GetMethod("TheMethod"); // can't Invoke() this one...
// ...later perhaps... MyType<ushort>.TheMethod()
var Tclose = Topen.MakeGenericType(typeof(ushort));
var mi = MethodInfo.GetMethodFromHandle(mi_open.MethodHandle, Tclose.TypeHandle);
var ret = (int)mi.Invoke(null, null); // works --> 0x02000150
// later yet... MyType<Guid>.TheMethod(), reusing 'mi_open' (and Topen)...
Tclose = Topen.MakeGenericType(typeof(Guid));
mi = MethodInfo.GetMethodFromHandle(mi_open.MethodHandle, Tclose.TypeHandle);
ret = (int)mi.Invoke(null, null); // works --> 0x020000eb
}
Notice that the Tclose type handle (passed in as the second arg) is not simply the handle of the type argument T that you ultimately want to parametrize with. Rather, you have to use that T to close the original Topen (open) generic type first, and then use the handle for the resulting (closed) generic type.
In other words, you can't close a method without first explicitly closing its generic type.
Lets say i have the following code
private Func<T> _method;
public void SetExecutableMethod<T>(Func<T> methodParam)
{
_method = methodParam;
}
public T ExecuteMethod(object[] parameterValues)
{
//get the number of parameters _method has;
var methodCallExpression = _method.Body as MethodCallExpression;
var method = methodCallExpression.Method;
ParameterInfo[] methodParams = method.GetParameters();
//So i now have a list of parameters for the method call,
//How can i update the parameter values for each of these?
for (int i = 0; i < parameters.Count(); i++ )
{
methodParams[i] = ???''
}
return _method.Compile()();
}
public void InitAndTest()
{
SetExecutableMethod( () => _service.SomeMethod1("param1 placeholder", "param2 placeholder") );
T result1 = ExecuteMethod(new object[]{"Test1", "Test2"});
T result2 = ExecuteMethod(new object[]{"Test3", "Test4"}););
}
In the above code, i want to set a private variable to some Func that points to an anonymoust function and never have to set it again.
I then would like to be able to call ExecuteMethod(...) with different parameters. This method should update the parameter values of the variable _method and then invoke the method.
I can read the number of parameters and their values fine, i just am not sure how to set the values for those parameter? Any thoughts on this?
This is not the way to do it. Right now, your _method field is a delegate of type Func<T>, and you expect that its body contains yet another method which is actually executed. That is a lot to expect from your callers. I would forget about this approach and look for something different.
One way would be to supply a method which takes an array of objects as its parameter (Func<object[], T>), and then invoke it directly with appropriate parameters (but never a method in its body). Even this is less common for a strongly typed language like C# since you lose all type safety (but then again, you do want to be pretty flexible with this framework you are designing).
The other way would be to get a MethodInfo instance, and then use its Invoke method. In a way, this might even express your intents better, because it will be obvious that the executable method is capable of virtually anything.
Next, you could use generics to get some type safety, and require that all your input parameters are wrapped inside a single parameter class. In that case, you might have a strongly typed Func<Tparam, Tresult> method, and your Execute method would accept a Tparam instance as its parameter. This would void the need for any reflection.
[Edit]
As I wrote, I would try to avoid reflection. Since you wrote you basically need a cache of method results, a simple approach might be something like:
Create a wrapper for your list of parameters so that you can compare them "by value". I added an example class, but you might even want to allow passing an IEqualityComparer explicitly, so that you don't have to override Equals for each partial parameter.
// implements `IEquatable` for a list of parameters
class Parameters : IEquatable<Parameters>
{
private readonly object[] _parameters;
public Parameters(object[] parms)
{
_parameters = parms;
}
#region IEquatable<Parameters> Members
public bool Equals(Parameters other)
{
if (other == null)
return false;
if (_parameters.Length != other._parameters.Length)
return false;
// check each parameter to see if it's equal
// ...
}
public override bool Equals(object obj)
{
return Equals(obj as Parameters);
}
public override int GetHashCode()
{ ... }
#endregion
}
Create a cache for a single service. Using the wrapper class above, it should simply check if a cached result exists:
// contains cached results for a single service
class CachedCallInfo
{
private readonly Func<object[], object> _method;
private readonly Dictionary<Parameters, object> _cache
= new Dictionary<Parameters, object>();
public CachedCallInfo(Func<object[], object> method)
{
_method = method;
}
public T GetResult<T>(params object[] parameters)
{
// use out Parameters class to ensure comparison
// by value
var key = new Parameters(parameters);
object result = null;
// result exists?
if (!_cache.TryGetValue(key, out result))
{
// do the actual service call
result = _method(parameters);
// add to cache
_cache.Add(key, result);
}
return (T)result;
}
}
Create the final class which will reference services by name:
public class ServiceCache
{
private readonly Dictionary<string, CachedCallInfo> _services =
new Dictionary<string, CachedCallInfo>();
public void RegisterService(string name, Func<object[], object> method)
{
_services[name] = new CachedCallInfo(method);
}
// "params" keyword is used to simplify method calls
public T GetResult<T>(string serviceName, params object[] parameters)
{
return _services[serviceName].GetResult<T>(parameters);
}
}
Your cache setup will then look like this:
serviceCache.RegisterService("ServiceA", #params => DoSomething(#params));
serviceCache.RegisterService("ServiceB", #params => SomethingElse(#params));
And you would simply call it like this:
var result = serviceCache.GetResult("ServiceA", paramA, paramB, paramC);
Not sure why this is useful, but here goes:
public class SomeCrazyClass<T>
{
private Expression<Func<T>> _method;
public void SetExecutableMethod(Expression<Func<T>> methodParam)
{
_method = methodParam;
}
public object ExecuteMethod(SomeService someService, object[] parameterValues)
{
var methodCallExpression = _method.Body as MethodCallExpression;
var method = methodCallExpression.Method;
var methodCall = Expression.Call(Expression.Constant(someService), method,
parameterValues.Select(Expression.Constant));
return Expression.Lambda(methodCall).Compile().DynamicInvoke();
}
}
Call it like so:
public static void InitAndTest()
{
var something = new SomeCrazyClass<int>(); //or whatever type your method returns
var _service = new SomeService();
something.SetExecutableMethod(() => _service.SomeMethod1("param1 placeholder", "param2 placeholder"));
var result1 = something.ExecuteMethod(_service,new object[] {"Test1", "Test2"});
var result2 = something.ExecuteMethod(_service, new object[] {"Test3", "Test4"});
}
Personally, I think you're going WAY overboard, unless there is an overriding architecture need to deal with the lambda as an expression tree. But, I digress.
Instead of working with the reflective elements (which are basically for description only in terms of an expression tree), look at the Arguments member of your MethodCallExpression. It will contain several ContantExpression objects, which you can replace with your own ConstantExpressions containing the string values you want to pass in. However, Expressions are read-only; you have to rebuild an equivalent tree for this call.
public class FuncManipulator<T>
{
private Func<T> _method;
public void SetExecutableMethod(Func<T> methodParam)
{
_method = methodParam;
}
//you forgot the "params" keyword
public T ExecuteMethod(params object[] parameterValues)
{
//get the number of parameters _method has;
var methodCallExpression = _method.Body as MethodCallExpression;
var arguments = methodCallExpression.Arguments;
var newArguments = new List<Expression>();
for (int i = 0; i < arguments.Count(); i++ )
{
newArguments.Add(Expression.Constant(parameterValues[i]));
}
//"Clone" the expression, specifying the new parameters instead of the old.
var newMethodExpression = Expression.Call(methodCallExpression.Object,
methodCallExpression.Method,
newArguments)
return newMethodExpression.Compile()();
}
}
...
public void InitAndTest()
{
SetExecutableMethod( () => _service.SomeMethod1("param1 placeholder", "param2 placeholder") );
T result1 = ExecuteMethod("Test1", "Test2");
T result2 = ExecuteMethod("Test3", "Test4");
T result3 = ExecuteMethod("Test6", "Test5");
}
This will work as long as the expression tree can find the Func referred to by MethodCallExpression.method within the current instance.
However, I think there's a much simpler way:
public class FuncManipulator<T>
{
private Func<T> _method;
public void SetExecutableMethod(Func<T> methodParam)
{
_method = methodParam;
}
//you must pass the actual array; we are creating a closure reference that will live
//as long as the delegate
public void SetMethodParams(object[] param)
{
_param = param;
}
public T ExecuteMethod(params object[] passedParam)
{
//We have to re-initialize _param based on passedParam
//instead of simply reassigning the reference, because the lambda
//requires we don't change the reference.
for(int i=0; i<_param.Length; i++)
_param[i] = passedParam.Length <= i ? null : passedParam[i];
//notice we don't pass _param; the lambda already knows about it
//via the reference set up when declaring the lambda.
return _method();
}
}
...
public void InitAndTest()
{
//this is an "external closure" we must keep in memory
object[] param = new object[2];
SetExecutableMethod( () => _service.SomeMethod1(param[0], param[1]) );
//We do so by passing the reference to our object
SetMethodParams(param);
//now, don't ever reassign the entire array.
//the ExecuteMethod function will replace indices without redefining the array.
T result1 = ExecuteMethod("Test1", "Test2");
T result2 = ExecuteMethod("Test3", "Test4");
T result3 = ExecuteMethod("Test6", "Test5");
}
Is it possible to create a generically typed Action at run time based on some specified types? In this particular scenario, the body of the Action will ultimately ignore the argument types, as the typed Action<> will just be a wrapper around a no-argument Action, e.g.
Action original = () => { };
...
Action<TType> wrapper = (arg) => {
original();
}
Or, even:
Action<TTypeA, TTypeB> wrapper = (arg) => {
original();
}
As you can see, the body of the typed Action<> ignores the arguments, and their type, it's just acting as a wrapper.
If you're curious as to why I want create this wrapper in the first place, the 'basic' version is that I am ultimately converting the Action to a Delegate for doing a Delegate.Combine(), which requires identical types. All I am trying to accomplish with the Delegate.Combine() is a basic notification that the delegate was fired.
At this point I will probably re-work my design to avoid these types of shenanigans, but I am still very curious how this might be accomplished.
The closest I could get was the following:
private static TType GetTypedDelegate<TType>(Action onComplete)
where TType : class
{
MethodInfo info = typeof(TType).GetMethod("Invoke");
ParameterInfo[] parameters = info.GetParameters();
object result;
if (parameters.Length == 0)
result = onComplete;
else if (parameters.Length == 1)
result = GetTypedDelegate<TType>(onComplete, parameters[0].ParameterType);
// etc
TType onCompleteCasted = Delegate.CreateDelegate(typeof(TType), result, "Invoke") as TType;
return onCompleteCasted;
}
private static Delegate GetTypedDelegate<TType>(Action onComplete, Type type)
{
// This line isn't useful for me right now, since I can't just create a new
// instance of the action with a parameterless constructor ... but I thought I'd throw it in here in case it was of use
Type actionType = typeof(Action<>).MakeGenericType(new[] { type });
// Do some magic here with the type information
// The following of course does not work,but you get the idea of what I am aiming for
Action<type> wrapper = (arg1) =>
{
onComplete();
};
return wrapper as Delegate;
}
I think that the easiest option is to write a generic method and then invoke it dynamically (using Reflection or possibly even using C# 4 dynamic):
class Helper {
public static Action<TType> Wrap1<TType>(Action arg) {
return (arg) => { original(); }
}
}
Invoking the method using Reflection and using typ1 as the generic type argument could look like this:
var meth = typeof(Helper).GetMethod("Wrap1");
var gmeth = meth.MakeGenericMethod(new[] { typ1 });
var genericAction = gmeth.Invoke(null, new object[] { action });
If you don't want to use reflection you can setup some classes like this.
public class ActionWrapper<TTypeA>
{
protected readonly Action _original;
public ActionWrapper(Action original)
{
_original = original;
}
public Action<TTypeA> Wrapped { get { return WrappedAction; } }
private void WrappedAction(TTypeA a)
{
_original();
}
}
public class ActionWrapper<TTypeA,TTypeB>:ActionWrapper<TTypeA>
{
public ActionWrapper(Action original) : base(original)
{
}
public new Action<TTypeA, TTypeB> Wrapped { get { return WrappedAction; } }
private void WrappedAction(TTypeA a,TTypeB b)
{
_original();
}
}
How can I get the custom attributes of a method from a Action<T> delegate?
Example:
//simple custom attribute
public class StatusAttribute : Attribute
{
public string Message { get; set; } = string.Empty;
}
// an extension methodto wrap MethodInfo.GetCustomAttributes(Type, Bool) with
// generics for the custom Attribute type
public static class MethodInfoExtentions
{
public static IEnumerable<TAttribute> GetCustomAttributes<TAttribute>(this MethodInfo methodInfo, bool inherit) where TAttribute : Attribute
{
object[] attributeObjects = methodInfo.GetCustomAttributes(typeof(TAttribute), inherit);
return attributeObjects.Cast<TAttribute>();
}
}
// test class with a test method to implment the custom attribute
public class Foo
{
[Status(Message="I'm doing something")]
public void DoSomething()
{
// code would go here
}
}
// creates an action and attempts to get the attribute on the action
private void CallDoSomething()
{
Action<Foo> myAction = new Action<Foo>(m => m.DoSomething());
IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true);
// Status Attributes count = 0? Why?
}
I realize I could do this by using reflection on Foo, but for what I'm trying to create I have to use an Action<T>.
The problem is that the action doesn't directly point at Foo.DoSomething. It points at a compiler-generated method of the form:
private static void <>__a(Foo m)
{
m.DoSomething();
}
One option here would be to change it to an Expression<Action<T>>, then you can dissect the expression tree afterwards and extract the attributes:
Expression<Action<Foo>> myAction = m => m.DoSomething();
var method = ((MethodCallExpression)myAction.Body).Method;
var statusAttributes = method.GetCustomAttributes<StatusAttribute>(true);
int count = statusAttributes.Count(); // = 1
The issue is that the lambda m => m.DoSomething() is not the same as DoSomething. It is a lambda expression which gets compiled into a method call on a compiler-generated method, possibly using a compiler-generated type (though maybe not the latter, since there are no captured local variables).
A very verbose way of getting an Action<Foo> from an instance (non-static) method of the Foo type is this:
var myAction = (Action<Foo>)Delegate.CreateDelegate(
typeof(Action<Foo>),
null, // treat method as static, even though it's not
typeof(Foo).GetMethod("DoSomething", BindingFlags.Instance | BindingFlags.Public)
);
Obviously, that is far from ideal and probably in fact useless in your case; but it's worth knowing ;)
Update: Actually, it just occurred to me you could write a quick extension method to make this easy for any instance method that you want to wrap as a static method (and maintain the "correct" MethodInfo):
public static class ActionEx
{
public static Action<T> ToStaticMethod<T>(this Action action)
{
if (!(action.Target is T))
{
throw new ArgumentException("Blah blah blah.");
}
return (Action<T>)Delegate.CreateDelegate(
typeof(Action<T>),
null,
action.Method
);
}
}
This would allow you to do:
Action<Foo> myAction = new Action(new Foo().DoSomething).ToStaticMethod<Foo>();
Admittedly, it's not as nice as m => m.DoSomething(); but it does give you an Action<T> whose Method property actually references the DoSomething method directly.
Alternately, instead of an Action<T>, you could use an Expression<Action<T>> and get the MethodInfo from that. Note that the syntax looks just the same in this case:
Action<Foo> myAction = m => m.DoSomething();
Expression<Action<Foo>> myExpression = m => m.DoSomething();
But that is a tricky proposition since an arbitrary Expression<Action<T>> is not guaranteed to be as simple as just m => m.DoSomething().
None of previous answers (except #Marc Gravell♦ 's which has no user's code) seems to be compilable :)
So I would propose mine:
private static void CallDoSomething()
{
var f = new Foo();
Action myAction = f.DoSomething;
IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true);
}