I read that MethodInfo only have information only about the method, nothing about the instance that come from, but there is some trick to the get instance to invoke the method as part of that instance?
For example:
MethodInfo someMethodInfo;
var obj = GetMethodInstance(someMethodInfo);
someMethodInfo.Invoke(obj, null);
The MethodInfo is not associated with any Instance, it discovers the attributes of a method and provides access to method metadata.
The MethodInfo class represents a method of a type. You can use a MethodInfo object to obtain information about the method that the object represents and to invoke the method.
MethodInfo is reflected directly from the Type definition, and as such has no relationship to any particular instance of the type, infact to get the Method Info you must generally get the type either directly with typeof() (so without even having an instance) or by first getting the type definition from obj.GetType().
So already the type definition is divorced from the original instance before you even attempt to get the MethodInfo, hence it would be harder again to obtain the original instance, if there was an instance at all to get.
Check if you can workaround using Delegates, otherwise look at the process where you obtain the methodinfo, and at that time pass through this to keep a reference to the object so that you don't have to try looking for it in the first place.
Related
When can I expect two references to PropertyInfo that represent the same property to not be the same instance?
E.g. If I get the PropertyInfo for a given class's property twice, I am typically returned the same instance both times:
var propertyOne = typeof(Foo).GetProperty(nameof(Foo.Bar));
var propertyTwo = typeof(Foo).GetProperty(nameof(Foo.Bar));
Console.WriteLine(propertyOne == propertyTwo); // Writes "True"
It is my understanding that this is not guaranteed, but under the hood .NET is caching the instance of PropertyInfo and returning it again on the second call to GetProperty(...).
I have hit a scenario (when debugging in VS), where two property instances representing the same property on the same concrete class ended up not being equal (according to Equals(...)). I was able to check the details of the objects and could see that they had the same property name and type, and the same reflected type property etc., but were separate instances. In my case the instances of PropertyInfo are actually obtained from the body of a LambdaExpression. After hitting this during debugging, I have been completely unable to reproduce it, and always end up with the same instance of PropertyInfo no matter how I try to obtain it. I can find no trace of it occuring in our logs either. I expect I will switch the way I am comparing the instances to not rely on reference equality, but am just curious as to how it might occur or could be reproduced.
Under what conditions can it occur that different instance of PropertyInfo are returned?
Hmmm, interesting question. Lets see how far I can get from reading the source code.
Starting with an expression;
Expression<Func<C,bool>> expr = c => c.X;
C# compiles this to IL;
IL_0001: ldtoken method instance bool C::get_X()
IL_001c: call class [System.Runtime]System.Reflection.MethodBase [System.Runtime]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [System.Runtime]System.RuntimeMethodHandle)
IL_0021: castclass [System.Runtime]System.Reflection.MethodInfo
IL_0026: call class [System.Linq.Expressions]System.Linq.Expressions.MemberExpression [System.Linq.Expressions]System.Linq.Expressions.Expression::Property(class [System.Linq.Expressions]System.Linq.Expressions.Expression, class [System.Runtime]System.Reflection.MethodInfo)
In other words calling Expression.Property(..., MethodInfo) with the MethodInfo representing the getter of the property, to build the LambdaExpression at runtime.
This Property method then searches mi.DeclaringType.GetProperties() for a static / instance property with the same get / set method. With a slight complication if mi.DeclaringType.IsInterface;
// If the type is an interface then the handle for the method got by the compiler will not be the
// same as that returned by reflection.
// Check for this condition and try and get the method from reflection.
So not all MethodInfos are .Equal()? Which sounds like a strange workaround, but maybe that could explain the difference you are seeing? Do you ever build a LambdaExpression based on an interface rather than a concrete type?
I have a method receiving a function, usually a method. From that function I can access to the method's class and other stuff using MethodInfo.
I want to be able to access the instance used, if any, when passing the function/method.
Example:
MyFunctionReceivingAMethod(new SomeClass().MethodA)
I want to access at MyFunctionReceivingAMethod to SomeClass instance from MethodA's reflection data. Is that possible?
Update:
I know I can pass the reference to the method but I wonder if its possible to get it using the funtion pointer I already have.
The reflection data in the MethodInfo class are associated with the method in general, not with any particular instance. Thus, you can't get the information you're looking for from that class.
Instead, the Delegate.Target property will return the instance associated with the received delegate (which I'm assuming is what you're looking for). According to its description on MSDN, the property returns:
The object on which the current delegate invokes the instance method, if the delegate represents an instance method; null if the delegate represents a static method.
Assume we have a static method "Instance" in a type: "SomeType"
MethodInfo instanceMethod = SomeType.GetMethod("Instance");
The method returns an object of a type that is not available in my code as it does not reference the assembly where that class is defined.
I would like then, to cast it to "object"
Like this:
Delegate.CreateDelegate(typeof(Func<object>), null, "Instance")
However I get this exception:
System.ArgumentException: Error binding to target method.
The CreateDelegate overload that you appear to be using only works for instance methods, not static ones. If you pass the MethodInfo instead of the name "Instance", you'll be using an overload that will work.
Also, Func<object> isn't compatible with just any type. You can create a Func<> that matches the method's return type with MakeGenericType.
Type funcType = typeof(Func<>).MakeGenericType(instanceMethod.ReturnType);
Delegate del = Delegate.CreateDelegate(funcType, null, instanceMethod);
As an aside, I'd name the method GetInstance instead of Instance, to make things clearer. (if it were a property, Instance would be appropriate)
I have a generic static method which registers a interface and I need to write that using c# reflection.
Services.AddService<ITBroker>(new TBrokerService());
I tried following code but it is not working
Type[] externTBrokerService = Assembly.LoadFrom("Business.dll").GetTypes();
Type[] externService = Assembly.LoadFrom("ServiceModel.dll").GetTypes();
Type iTBroker = externITBroker[12];
MethodInfo method = externService[1].GetMethods()[2];
//Gets Add Service method
MethodInfo generic = method.MakeGenericMethod(iTBroker);
//Make method generic
generic.Invoke(null,new object[] { externTBrokerService[0]});
//invoke the service
Above code gives me very generic exception of parameters.
What is the write way to write reflection for above code?
As it was in comments:
Note that externTBrokerService[0] is a Type and not an instance of that type.
Having that I feel a need to include sense of other comments as part of my answer.
Type iTBroker = externITBroker[12];
this is wrong! And sooner or later this will fail to find your type as the order of types in this collection is undetermined and can change. You should do it like this:
Type iTBroker = externITBroker.Single(x => x.Name == "ITBroker");
This is far form foolproof so be sure that the condition gives you unique result.
or simply load that type directly by (assuming that this is the AssemblyQualifiedName of your type):
Type.GetType("Business.ITBroker, Business");
To find method on your type there is a method Type.GetMethod one of its overloads will be sufficient to find your method.
To create instance of your type that needs to be passed as argument you can use
Activator.CreateInstance(brokerServiceType);
In C# I want to create a generic method that:
Accepts a MethodInfo object as a parameter.
Returns the object that is returned when the MethodInfo is invoked.
The source of my confusion is that I want the method to be generically typed to the same return type as the MethodInfo object that gets passed in.
You cannot do this. By definition, generics are a compile-time construct, while the return type of a particular MethodInfo is something that is only known at runtime (when you receive a specific MethodInfo instance), and will change from call to call.
Pavel Minaev is right,
My suggestion in this case (of course i don't know the whole context) is use a method that returns a dynamic type, of course is that wouldn't be typed.
public dynamic MyMethod(MethodInfo methodInfo)
Or since you know what is the return type, put that in the method call:
public T MyMethod<T>(MethodInfo methodInfo)
of course you gonna get in trouble inside the method mapping the conversions.
but you can also put the conversion in a parameter using lambda, like:
public T MyMethod<T>(MethodInfo methodInfo, Func<object, T> conversion)
i think the call of the method will be very clear, like:
Console.WriteLine(MyMethod(methodInfo, (a) => Convert.ToString(a)));