Given a null cast:
var result = MyMethod( (Foo) null );
Is it possible to use this extra information inside the method with reflection?
EDIT:
The method's signature is something like:
object MyMethod( params object[] args )
{
// here I would like to see that args[0] is (was) of type Foo
}
Ahh... you edited...
I suspect the closest you'll get is generics:
object MyMethod<T>( params T[] args ) {...}
(and look at typeof(T))
But that assumes all the args are the same. Other than that; no. Every null is the same as every other (Nullable<T> aside), and you cannot tell the variable type.
Original reply:
Do you mean overload resolution?
object result = someType.GetMethod("MyMethod",
new Type[] { typeof(Foo) })
.Invoke(someInstance, new object[] { null });
(where someInstance is null for static methods, and someType is the Type that has the MyMethod method)
Short answer: No
I'm guessing you got something like this:
class Foo : Bar{}
Since you've got:
object MyMethod(param object[] values);
There's no way to do this. You could use a null object pattern to accomplish this:
class Foo : Bar
{
public static readonly Foo Null=new Foo();
}
and then call with Foo.Null instead of null. Your MyMethod could then check for the static instance and act accordingly:
object MyMethod(param object[] values
{
if(values[0]==Foo.Null) ......
}
Related
In the code below, how should I be setting the variable "paramType" so that it matches the method shown in the GetMethod() call?
The code below does NOT match the method in the sample class (methodInfo is null).
using System;
using System.Linq.Expressions;
public class MyClass<TClass>
{
public void MyMethod<TMethod>( Expression<Func<TClass, TMethod>> expr )
{
}
}
class Program
{
static void Main( string[] args )
{
var classType = typeof( MyClass<> );
// What should this really be?
var paramType = typeof( Expression<> ).MakeGenericType( typeof( Func<,> ) );
var methodInfo = classType.GetMethod( "MyMethod", new Type[] { paramType } );
}
}
EDIT: I know how to get the MethodInfo using GetMethods or some other form of iteration / assumption. My question is specifically about how to set the System.Type of paramType, if its even possible to generate a System.Type for it.
EDIT 2: To be more specific with the problem, I've updated the code with more flavor:
using System;
using System.Linq.Expressions;
public class MyClass<TClass>
{
public void MyMethod<TMethod>( Expression<Func<TClass, TMethod>> expr )
{
Console.WriteLine( "Type: {0} Return: {1}", typeof( TClass ).Name, typeof( TMethod ).Name );
}
public void MyMethod<TMethod>( TMethod param )
{
}
}
class Program
{
public int MyProperty { get; set; }
static void Main( string[] args )
{
var classType = typeof( MyClass<> );
var typeClass = typeof( Program );
var typeMethod = typeof( int );
// What should this really be?
var paramType = typeof( Expression<> )
.MakeGenericType( typeof( Func<,> )
.MakeGenericType( typeClass, typeMethod )
);
var methodInfo = classType
.MakeGenericType( typeClass )
.GetMethod( "MyMethod", new Type[] { paramType } );
}
}
This doesn't work either- this different version of paramType with more information doesn't seem to match.
In the non-general case, someone may want to call "MyMethod" like this:
// I want to use a MethodInfo to perform this function:
new MyClass<Program>().MyMethod( _program => _program.MyProperty );
I believe the answer to your question is, "There is no way to do this".
Since GetMethod is not able to "MakeGenericMethod" while its doing its lookup, you have a method with one generic parameter that's known (TClass) and one that's not (TMethod). Reflection can't look up a method when some, but not all, of the parameters are known.
Note- Even though you do know what TMethod is supposed to be ("int" in your example), this would require the "MakeGenericMethod" that I referenced in the previous paragraph.
To do this you need to know the generic types, I don't think your task would be possible otherwise.
If your intention was to create a generic methodinfo for a generic class, before it knows any of its types, so you can later call MakeGenericType with your two types on it, that won't possible.
This can be shown by calling typeof(MyClass<>).GetMethod("MyMethod"), which will return null.
If you know the specific types on the other hand, that's easy:
static MethodInfo GetMethod(Type classType, Type methodType)
{
var genericClassType = typeof(MyClass<>).MakeGenericType(classType);
var methodInfo = genericClassType.GetMethod("MyMethod");
var genericMethodInfo = methodInfo.MakeGenericMethod(methodType);
return genericMethodInfo;
}
Notice that I don't create a generic type for the Expression<Func<TClass,TMethod>> parameter.
When you create the genericClassType and call GetMethod on it, the CLR doesn't know yet, what type TMethod would be. This is only know as soon as you call MakeGenericType on methodInfo. Therefore if you would call GetMethod with a fully parametrized Expression<Func<TClass,TMethod>> type, it wouldn't find the method.
That's why you need to call genericClassType.GetMethod("MyMethod") without the parameter types and possibly have to filter it, if the method is overloaded. Afterwards you can call MakeGenericMethod(methodType) and have your fully parametrized methodInfo object.
I have a class which contains an empty constructor and one that accepts an array of objects as its only parameter. Something like...
public myClass(){ return; }
public myClass(object[] aObj){ return; }
This is the CreateInstance() method call that I use
object[] objectArray = new object[5];
// Populate objectArray variable
Activator.CreateInstance(typeof(myClass), objectArray);
it throws System.MissingMethodException with an added message that reads
"Constructor on type 'myClass' not found"
The bit of research that I have done has always shown the method as being called
Activator.CreateInstance(typeof(myClass), arg1, arg2);
Where arg1 and arg2 are types (string, int, bool) and not generic objects.
How would I call this method with only the array of objects as its parameter list?
Note: I have tried adding another variable to the method signature. Something like...
public myClass(object[] aObj, bool notUsed){ return; }
and with this the code executed fine.
I have also seen methods using reflection which were appropriate but I am particularly interested in this specific case. Why is this exception raised if the method signature does in fact match the passed parameters?
Cast it to object:
Activator.CreateInstance(yourType, (object) yourArray);
Let's say you have constructor:
class YourType {
public YourType(int[] numbers) {
...
}
}
I believe you would activate like so by nesting your array, the intended parameter, as a item of the params array:
int[] yourArray = new int[] { 1, 2, 4 };
Activator.CreateInstance(typeof(YourType ), new object[] { yourArray });
is it possible to make generic function in c# that get as input some class and method (of the class) and parameters to the method ( and maybe the result type ) and make instance of that class and call to the function of the class with the parameters and return the result?
Sure.
public class MyClass
{
public class Test
{
public int TestMethod(int a, int b)
{
return a + b;
}
}
public static void Main()
{
int result = ExecuteMethod<Test, int>("TestMethod", 1, 2);
Console.Read();
}
public static TResult ExecuteMethod<TClass, TResult>(string methodName, params object[] parameters)
{
// Instantiate the class (requires a default parameterless constructor for the TClass type)
var instance = Activator.CreateInstance<TClass>();
// Gets method to execute
var method = typeof(TClass).GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
// Executes and returns result
return (TResult)method.Invoke(instance, parameters);
}
}
Unless Reflection is your absolute option, use one of the following delegates:
Action<T>: Will let you execute a method that does not return a value. There are several overloads that will let you pass in additional arguments.
Func<TResult>: Will let you execute a method that returns a result of type TResult. There are more overloads that will let you pass in additional arguments. They all follow the syntax Func<T1, T2, T3, TResult> and so on.
And finally, you can define your own delegate.
Yes it's possible. You can do that with reflection.
Here you have a few useful links
Create an instance with reflection
How to invoke method with parameters
Here's how you create an instance of a class using reflection and then call a method on that class.
Assuming you have a class:
public class MyType
{
public void DoSomething()
{
// do stuff here
}
}
You could do the following:
Type instanceType = Type.GetType("MyType");
object instance = Activator.CreateInstance(instanceType);
MethodInfo method = instanceType.GetMethod("MethodName");
object returnValue = method.Invoke(instance, new object[] { /* paramaters go here */ });
I am trying to instantiate a type using Activator's reflection magic. Unfortunately the type I want to instantiate has a params parameter of type object. See this extract:
public class Foo
{
public Foo(string name, params object[] arguments)
{
}
}
And the instantiation goes here:
public static class Bar
{
public static object Create(params object[] arguments)
{
return Activator.CreateInstance(typeof(Foo), "foo", arguments);
}
}
Now, this effectively results in a constructor call with the signature
new Foo(string, object[])
because object[] is also object.
What I actually want is:
new Foo(string, object, object, object, ...)
Is this even possible with Activator? Or how do I instantiate a type with such a parameter type?
params is a purely-compile-time syntactic sugar.
The runtime, including the parameter binding used by reflection, ignores it.
You need to pass a normal array, just like a non-params parameter.
In your case, it sounds like you're trying to not call the params overload.
You need to build a single (flattened) array containing all of the parameters you want to pass:
object[] args = new object[arguments.Length + 1];
args[0] = "foo";
arguments.CopyTo(args, 1);
You can pass parameters like this:
return Activator.CreateInstance(
typeof(Foo),
new object[] { "foo" }.Concat(arguments).ToArray());
No doubt elements of this question have been asked before, but I'm having trouble finding an answer. (Disclaimer: this is related, but separate from a recent question I asked).
I have a method like this:
public static void Method<T>(MethodInfo m, T value)
{
Type memberType = m.GetValueType();
if (memberType.IsAssignableFrom(typeof(List<T>))
{
object memberValue = Activator.CreateInstance(memberType);
((List<T>)memberValue).Add(value);
}
}
This works fine when I call it like this:
string s = "blah";
Method(memberInfo, s);
However, I need to call this method using a generic type, so I'm calling it like this:
Type valueType = someType;
object passValue = someMethod.MakeGenericMethod(new Type[] { valueType }).Invoke(this, new object[] { });
/* Call my original method */
Method(memberInfo, passValue );
Now, intellisense knows that 'value' in Method<T> is whatever type valueType is (say 'FooObject'). But 'T' is object, which means that a List<FooObject> is not assignable from a List<T> (i.e. a List<object>).
I've tried using Convert.ChangeType on the variable ('passValue') beforehand but that wasn't any more useful.
As there is no way to cast a variable to the Type of a type variable, how do I get around this?
Is the best solution to somehow not rely on IsAssignableFrom and do a looser type check of whether this will work? The problem with this is that I'm not sure I'll be able to cast the memberValue properly unless 'T' is truly the element type of memberValue.
This should give you a callable method (I'll test it in a little while). The boxing/unboxing it incurs is much faster than the security checks required for the Reflection API invocation (which happens to also require boxing).
private static Action<MethodInfo, object> BuildAccessor(Type valueType)
{
MethodInfo genericMethod = null; // <-- fill this in
MethodInfo method = genericMethod.MakeGenericMethod(new Type[] { valueType });
ParameterExpression methodInfo = Expression.Parameter(typeof(MethodInfo), "methodInfo");
ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
Expression<Action<MethodInfo, object>> expr =
Expression.Lambda<Action<MethodInfo, object>>(
Expression.Call(method, methodInfo, Expression.Convert(obj, valueType)),
methodInfo,
obj);
return expr.Compile();
}
You're in luck. I actually had to do something very similar a few weeks ago.
For a detailed explanation see the above blog post, but basically the general idea is to reflect the type and manually invoke the method with an explicit set of parameters.
typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param });
It's not very type safe, but it does exactly what you're looking for.
class Program
{
static void Main(string[] args)
{
object str = "Hello World";
object num = 5;
object obj = new object();
Console.WriteLine("var\tvalue\t\tFoo() Type\tCallFoo() Type");
Console.WriteLine("-------------------------------------------------------");
Console.WriteLine("{0}\t{1}\t{2}\t{3}", "str", str, MyClass.Foo(str), MyClass.CallFoo(str));
Console.WriteLine("{0}\t{1}\t\t{2}\t{3}", "num", num, MyClass.Foo(num), MyClass.CallFoo(num));
Console.WriteLine("{0}\t{1}\t{2}\t{3}", "obj", obj, MyClass.Foo(obj), MyClass.CallFoo(obj));
}
}
class MyClass
{
public static Type Foo<T>(T param)
{
return typeof(T);
}
public static Type CallFoo(object param)
{
return (Type)typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param });
}
}
Output
var value Foo() Type CallFoo() Type
-------------------------------------------------------
str Hello World System.Object System.String
num 5 System.Object System.Int32
obj System.Object System.Object System.Object