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
Related
I want invoke Method2 which is an extension method of a MyClass using MyClass type. I am wondering if this is possible or not.
using System;
using System.Linq;
using System.Reflection;
namespace ConsoleApplication9
{
public static class MyClassStatic
{
public static void Method2(this ConsoleApp2.MyClass obj)
{
Console.WriteLine("You have called ex Method 2");
}
}
public interface IClass
{
void Method1();
}
public class MyClass : ConsoleApp2.IClass
{
public void Method1()
{
Console.WriteLine("You have called Method 1");
}
}
class Program
{
public static void CallWhereMethod()
{
var whereMethods = typeof(MyClass)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Method2");
Console.WriteLine(whereMethods.Count());
// returns zero
}
static void Main(string[] args)
{
CallWhereMethod();
Console.ReadKey();
}
}
}
Actually, there is a way for this, but it's hard a bit. If you don't forget to place a this keyword to your extension method parameter, C# compiler will emmit ExtensionAttribute to this method and this class. Knowing this, you are able to find this extension method and execute it:
var myClassType = typeof(MyClass);
var myClass = new MyClass();
var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in assemblyTypes.Where(t => t.GetCustomAttribute<ExtensionAttribute>() != null)
{
var typeMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var method in typeMethods.Where(m => m.IsDefined(typeof(ExtensionAttribute), inherit: false))
{
if (method.GetParameters()[0].ParameterType == myClassType)
{
// here you go
method.Invoke(null, new object[]{ myClass });
}
}
}
If you unsure in which assembly to search for extension method, you may try to search all:
var allLoadedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes());
Please note: reflection is slow. Really slow. Even you filter all of your types with .Where(type => type.IsSealed) or any other filter, it is still dead slow. If you have any other way to invoke the code in your extension method, you probably should use that way.
Sure, it's possible, the only caveat is .Net Reflection doesn't understand the Extension Method syntactic-sugar of this.
Remembering, that an extension method is a C# construct to save you a couple of printable-characters when calling a static class static method when given the first parameter (labelled with the this keyword)
So in short, you'll have to target the static class and pass in the MyClass instance as the first parameter
var myClass = new MyClass();
var whereMethods = typeof(MyClassStatic)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(mi => mi.Name == "Method2");
whereMethods.Invoke(null, new object[]{ myClass } );
Output
You have called ex Method 2
Full Demo Here
Update
I don't want to use typeof(MyClassStatic). I want to use
typeof(MyClass)
Method2 is not a member of MyClass, and you can't force it to be as such in any way that I can think of.
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.
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);
}
I have a base class (MyBase) with lots of possible derived classes (in this example, MyDerived and MyDerived2). Along the way a List<MyBase> is handed off to another class, and then later on that class needs to call a constructor of yet another class... which constructor is called is based entirely on what's in the List.
I can use Reflection to find the constructor, but only if somewhere along the way I do something like:
var r = baseList.ConvertAll(x => (MyDerived1)x);
So that r contains a List<MyDerived1> and I can find the constructor through Reflection. This is silly, of course, because I could also just bake-in the constructor since I'm bothering to bake in MyDerived1 in that ConvertAll statement. But this is one derived class, and I have dozens.
What I want to do is have the method RunTest() call the right constructor based entirely on what it finds in the List<MyBase> at runtime. Looking at the first object in the list is fine, as a practical matter since they'll always be all of the same type.
Is this possible? How?
namespace Classtest
{
class Program
{
static void Main(string[] args)
{
Test t = new Test( new List<MyBase>() {
new MyDerived1(),
new MyDerived1() } );
t.RunTest();
}
}
public class Test
{
List<MyBase> baseList;
public Test(List<MyBase> bl)
{
baseList = bl;
}
public void RunTest()
{
// I would like the CreateInstance to figure out which constructor
// to call based on what it finds in baseList,
// without having to indicate "MyDerived1" here.
// This works, but I'd rather have it figure this out at
// runtime for every single possible derived class...
var r = baseList.ConvertAll(x => (MyDerived1)x);
Object o = Activator.CreateInstance(typeof(CallMe),
new object[] { r });
}
}
public class CallMe
{
public CallMe(List<MyDerived1> myDerived)
{
Console.WriteLine("Found it.");
}
public CallMe(List<MyDerived2> myDerived)
{
Console.WriteLine("Wrong one!");
}
}
public class MyBase
{ }
public class MyDerived1 : MyBase
{ }
public class MyDerived2 : MyBase
{ }
}
You can use MakeGenericType() to create a List<T> with the correct generic type:
public void RunTest()
{
// This method is creating a new list by doing the following:
// var r = new List<baseList[0].GetType>(
// baseList.Cast<baseList[0].GetType()>);
var elementType = baseList[0].GetType();
// Get the System.Linq.Enumerable Cast<elementType> method.
var castMethod = typeof(Enumerable)
.GetMethod("Cast", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(elementType);
// Create a List<elementType>, using the Cast method to populate it.
var listType = typeof(List<>).MakeGenericType(new [] { elementType });
var r = Activator.CreateInstance(listType,
new [] {castMethod.Invoke(null, new [] {baseList})});
Object o = Activator.CreateInstance(typeof(CallMe),
new [] { r });
}
If your CallMe constructors could be changed to take an IEnumerable<> parameter instead of List<>, then you could simplify RunTest() by removing the List<> creation:
public void RunTest()
{
var elementType = baseList[0].GetType();
// Get the System.Linq.Enumerable Cast<elementType> method.
var castMethod = typeof(Enumerable)
.GetMethod("Cast", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(elementType);
Object o = Activator.CreateInstance(typeof(CallMe),
new [] { castMethod.Invoke(null, new[] {baseList}) });
}
public void RunTest()
{
// it seems like you would want to run the following using reflection...
// var myBaseList = this.baseList.OfType<this.baseList[0].GetType()>().ToList();
Type[] genericTypeArray = new Type[] { this.baseList[0].GetType() };
// call OfType to get IEnumerable<this.baseList[0].GetType()>
MethodInfo ofTypeMethodInfo = typeof(Enumerable).GetMethods().Where(d => d.Name == "OfType").First();
ofTypeMethodInfo = ofTypeMethodInfo.MakeGenericMethod(genericTypeArray);
object myBaseEnumerable = ofTypeMethodInfo.Invoke(null, new object[] { this.baseList });
// call ToList to get List<this.baseList[0].GetType()>
MethodInfo toListMethodInfo = typeof(Enumerable).GetMethods().Where(d => d.Name == "ToList").First();
toListMethodInfo = toListMethodInfo.MakeGenericMethod(genericTypeArray);
object myBaseList = toListMethodInfo.Invoke(null, new object[] { myBaseEnumerable });
Object o = Activator.CreateInstance(typeof(CallMe), new object[] { myBaseList });
}
If CreateInstance can't find the right constructor, try typeof(...).GetConstructor() and pass in the right types. This will give you the right ctor, which you can invoke. I don't think there's another, non-reflection way, LINQ Cast<> and similar methods require the type to be statically known or given as a type parameter, which is not the case when you have a list which could contain anything.
UPDATE: Oh, it won't work, you can't pass a List<derived> to a List<base> constructor. Here's what you need: you need to call Cast<> with reflection. typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(list[0].GetType()). Then, you have a list with the correct type, so no need for constructor reflection, Activator will work with this.
public void RunTest()
{
if (baseList.Count > 0)
{
Type ctorParam = typeof(List<>).MakeGenericType(baseList[0].GetType());
object instance = typeof(CallMe).GetConstructor(new Type[] { ctorParam })
.Invoke(new object[] { baseList });
}
}