I have a number of 'jobs' in my application, where each job has a list of methods which it needs to call, along with it's parameters. Essentially a list containing the following object is called:
string Name;
List<object> Parameters;
So basically, when a job runs I want to enumerate through this list, and call the relevant methods. For example, if I have a method like the following:
TestMethod(string param1, int param2)
My method object would be like this:
Name = TestMethod
Parameters = "astring", 3
Is it possible to do this? I imagine reflection will be the key here.
Sure, you can do it like this:
public class Test
{
public void Hello(string s) { Console.WriteLine("hello " + s); }
}
...
{
Test t = new Test();
typeof(Test).GetMethod("Hello").Invoke(t, new[] { "world" });
// alternative if you don't know the type of the object:
t.GetType().GetMethod("Hello").Invoke(t, new[] { "world" });
}
The second parameter of Invoke() is an array of Object containing all the parameters to pass to your method.
Assuming the methods all belong to the same class, you could have a method of that class something like:
public void InvokeMethod(string methodName, List<object> args)
{
GetType().GetMethod(methodName).Invoke(this, args.ToArray());
}
If you're using .NET Framework 4, look at dynamic, otherwise GetMethod and then call Invoke of MethodInfo.
Use MethodBase.Invoke(). Should work down to .NET 2.0 with System.Reflection.
If you're using having to resort to reflection, there is probably a better way to accomplish your task. It may take a little more architecture, but it's doable.
Remember, having more code isn't a bad thing -- especially when it compliments the readability and manageability of your code. Reflection is difficult to understand for most, and you lose most of your compile time type safety. In your example, you could probably just get away with a switch statement and distinct objects for each method you were planning to call. e.g.
// Have some object hold the type of method it plans on calling.
enum methodNames
{
Method1,
Method2
}
...
class someObject
{
internal methodNames methodName {get; set;}
internal object[] myParams;
}
...
// Execute your object based on the enumeration value it references.
switch(someObject1.methodName)
{
case Method1:
Test.Method1(Int32.Parse(someObject1.myParams[0].ToString),someObject1.myParams[1].ToString());
break;
...
}
If you know that you only have a distinct set of method possibilities to call, why not just set yourself up ahead of time?
NuGet to the rescue! PM> Install-Package dnpextensions
Once you have that package in your project, all objects should now have a .InvokeMethod() extension, that will take the method name as a string and any number of parameters.
That does technically use "magic strings" for the method names, so if you wanted to strongly-type your method dictionary, you could make the keys of type MethodInfo and get them like this...
MethodInfo[] methodInfos = typeof(MyClass).GetMethods();
And then you can do something like this...
var methods = new Dictionary<MethodInfo, Object[]>();
foreach (var item in methods)
item.key.Invoke(null, item.value);
// 'null' may need to be an instance of the object that
// you are calling methods on if these are not static methods.
Or you could do some variation of the above block using the dnpextensions I mentioned earlier.
Related
I am wondering if it is possible to use a classes method when you only know the classes name by it's string value.
Let's say I have a class and within class I have a static method like
public class SomeClass
{
public static string Do()
{
//Do stuff
}
}
And when using class I want to something like
string str = (GetType(SomeClass)).Do();
When using the method I want to give the name of the class as string like I want to give SomeClass as a string.
var t = Type.GetType("MyNamespace.SomeClass");
var m = t.GetMethod("Do");
m.Invoke(null, new object[] { /* Any arguments go here */ });
You're going to have to use reflection throughout; for example:
object result = Type.GetType(typeName).GetMethod(methodName).Invoke(null, args);
Use Type.GetMethod to get the method info object of the method, then call MethodInfo.Invoke to execute it. For static methods, pass null as the first parameter (the object value):
Type type = typeof(SomeClass);
type.GetMethod("Do").Invoke(null, null);
If you don’t know the class name at compile time, you can also use object.GetType, Type.GetType or Assembly.GetType to get the type object at runtime (depending on what information you have available). Then, you can use it in the same way:
Type type = someObject.GetType(); // or Type.GetType("SomeTypeName");
type.GetMethod("Do").Invoke(null, null);
To be on the safe side, make sure to check whether GetMethod actually returns a method, so you have some confirmation that the method exists on that type then.
I have the following method with an overload:
public string GetName(object obj)
{
return obj.ToString();
}
public string GetName(CustomClass cc)
{
return cc.Name + " - " + cc.Description;
}
Now if I call the method with an untyped IEnumerable wich holds CustomClass the GetName(object obj) gets called, to fix this I have modified the method like this:
public string GetName(object obj)
{
if (obj is CustomClass)
return GetName(obj as CustomClass);
return obj.ToString();
}
I think its rather annoying to write 20 IF statements and catch all the other possibilities, is there an easier way to call the correct overload with an untyped IEnumerable enumeration?
Here is the code that calls the GetName(object obj):
IEnumerable rawData = GetData(); //DataBase method that fetches a CustomClass
foreach (var rawDataItem in rawData)
{
Debug.Print(GetName(rawDataItem)); //calls the GetName(object obj) overload
}
Pls dont tell me to override ToString from my CustomClass, help me fix this method calling problem.
Well, you could use dynamic typing. That will basically defer overload resolution until execution time:
foreach (dynamic rawDataItem in rawData)
{
Debug.Print(GetName(rawDataItem));
}
Note that there's potentially a performance cost here - it may well be minimal and insignificant, but it's worth being aware of.
EDIT: To handle the recursion side of things, you'd probably want two different names, e.g. GetName and GetNameImpl where GetName delegates to GetNameImpl which is what all the useful overloads are called. So you'd have:
// Note that dynamic as a parameter type is equivalent to object for callers.
// The dynamic part is only relevant within the method.
public string GetName(dynamic obj)
{
return GetNameImpl(obj);
}
// Fallback when no other overloads match
private string GetNameImpl(object obj)
{
...
}
private string GetNameImpl(IEnumerable obj)
{
// Maybe build up the name by calling GetName on each element?
}
Note that there's a potential problem with this: if you have two overloads for different interfaces and one type implements both interfaces (but there isn't a specific overload for that type itself) then you'll get an exception at execution time.
If you want callers to be able to call the overloads directly, you could just rename the dynamic one to GetNameDynamic and the others to GetName for example (and make them public).
I rarely find that dynamic is a good solution, but it would avoid the code duplication. I would try to step back and find a different design to be honest. You explicitly rejected it in the question, but polymorphism is the preferred way of handling this. You don't need to necessarily override ToString - you could make all of the custom types implement a particular interface, and use that where it's available, for example.
return GetName((dynamic)obj);
will postpone overload resolution till runtime.
Without dynamic typing, the classic OOP solution to supporting double dispatch (where the method called depends on both the concrete type of the object having the method and the concrete type of the passed object) is the visitor pattern.
Try this:
public string GetName(object obj)
{
if (!(obj is IEnumerable<object>))
return GetName(obj as CustomClass);
return obj.ToString();
}
In SignalR there is public property defined in the HubConnectionContext as such:
public dynamic All { get; set; }
This enables users to call it like: All.someMethodName(); which is brilliant.
I now would like to call this using an incoming parameter in my function. How can I do this?
As in: All.<my variable as method name>();
Is there any way of doing this?
Thanks
EDIT example:
public void AcceptSignal(string methodToCall, string msg)
{
Clients.All.someMethod(msg); // THIS WORKS
Clients.All.<methodToCall>(msg); // THIS DOES NOT WORK (But I would like it to!)
}
While I love all the fun reflection answers, there's a much simpler and faster way to invoke client hub methods using a string as the method Name.
Clients.All, Clients.Others, Clients.Caller, Clients.AllExcept(connectionIds), Clients.Group(groupName), Clients.OthersInGrouop(groupName), and Clients.Client(connectionId) are all dynamic objects, but they also all implement the IClientProxy interface.
You can cast any of these dynamic objects to an IClientProxy, and then call Invoke(methodName, args...):
public void AcceptSignal(string methodToCall, string msg)
{
IClientProxy proxy = Clients.All;
proxy.Invoke(methodToCall, msg);
}
You can use reflection to achieve this:
Type allType = All.GetType();
// GetType() may return null in relation to dynamics objects
if (allType != null)
{
MethodInfo methodInfo = allType.GetMethod(methodToCall);
methodInfo.Invoke(All, null);
}
public void AcceptSignal(String methodToCall, String msg) {
var count=(
from target in new[] { Clients.All }
from memberInfo in ((Type)target.GetType()).GetMember(methodToCall)
where MemberTypes.Method==memberInfo.MemberType
let methodInfo=memberInfo as MethodInfo
let paraInfos=methodInfo.GetParameters()
where null!=paraInfos.FirstOrDefault(x => msg.GetType()==x.ParameterType)
select methodInfo.Invoke(target, new object[] { msg })
).Count();
}
You can use reflection to find the method. But this will only work if it is a "real" non-dynamic method which is defined in the usual non-dynamic way, only hidden behind the dynamic keyword.
If however the object All is truely dynamic, like an ExpandoObject or something else deriving from System.Dynamic.DynamicObject, the "method" could be something that was only associated with the type at runtime, and in that case typeof(All).GetMethod won't find anything.
It was Ilya Ivanov who originally pointed this out, in a comment to John Willemse's answer. It became apparent that the object is a Microsoft.AspNet.SignalR.Hubs.ClientProxy instance.
Therefore, from the documentation of that type, the solution is:
string methodToCall = XXX;
string msg = YYY;
((ClientProxy)(Clients.All)).Invoke(methodToCall, msg);
I'm attempting to make a generic routine within my program that will instantiate objects for me. The routines actually responsible for calling new Object() are located within a different assembly in a factory that must be instantiated.
namespace ExternalLib
{
class Object1Factory
{
public Object1 getObject1()
//...
}
class Object2Factory
// Same implementation as Object1Factory
}
I am attempting to provide a routine with my application that will allow me to call the appropriate routine to "new up" the object for me.
namespace MyApp
{
class Program
{
static void Main()
//...
static Object getNewObject(string typeName)
{
//This is where I have problems
}
}
}
I have access to the source code of both the external library as well as my program, although an entire re-write of the architecture is too costly.
What I've tried:
My initial idea was to use custom attributes on the factory and/or factory routine and use reflection to grab the method, then call the method. I was originally using the signature private static T getNew<T>() and attempting to use a switch statement on the type parameter, but realised getNewObject(string typeName) would be easier. Factories have the same constructor signatures, but have no inheritance link.
In summation: Routine to create objects is in factory in another assembly, how do I automatically call those routines to get objects based on type?
If you want to continue down this path - can you put all of the factory methods in a single factory class called something like 'ObjectFactory'?
Type t = typeof(OtherAssembly.ObjectFactory);
MethodInfo m = t.GetMethods().Where(a => a.ReturnType.Name == typeName).FirstOrDefault();
return m.Invoke(null, new object[] { /* PARAMETERS */ });
EDIT - response to James's comment on question stating he'd prefer to keep factory classes separate:
(Using Martin's idea below and relies on all Factory classes being names "[Type]Factory")
(Also has non-static methods on factory class)
Type t = Type.GetType(String.Format("OtherAssembly.{0}Factory", typeName));
var myFactory = Activator.CreateInstance( t );
MethodInfo m = t.GetMethods().Where(a => a.ReturnType.Name == typeName).FirstOrDefault();
return m.Invoke(myFactory, new object[] { /* PARAMETERS */ });
Maybe I'm missing something in the question, but what's wrong with just using this:
static Object getNewObject(string typeName)
{
var type = Type.GetType(typeName);
return Activator.CreateInstance(type);
}
Maybe with a bit of string manipulation and reflection if typeName is say Object1 and you want to get hold of Object1Factory, and then using reflection to invoke the getObject1() method on the factory
If you can pass in typeName as say "MyNameSpace.Object1, Object1Assembly" then it will load it from the relevant assembly.
Purely in response to what you tried, if you alter the signature to:
static T GetNew<T>() where T : new()
{
// Then you can do this:
return new T();
}
It places a generic constraint for a public parameterless constructor on the type T. However, this is pointless as calling code would look like this:
var obj = GetNew<MyClass>();
Whereas it would normally just look like this:
var obj = new MyClass();
So I wouldn't go for it as a solution, but it would have worked and would have negated the need for the switch statement.
Is there a way to invoke a generic function with a type known only at run time?
I'm trying to do something like:
static void bar()
{
object b = 6;
string c = foo<typeof(b)>();
}
static string foo<T>()
{
return typeof (T).Name;
}
Basically I want to decide on the type parameter only at run time, but the function I'm calling depends on the type parameter.
Also I know this can be done with reflections... but it's not the nicest solution to the problem...
I'm sort of looking for dynamic features in C#...
I'm writhing a bridge between two classes the first one is basically a big tree with different types of of objects (composite by interface) the other is a sort of a "super visitor".
the supper visitor accepts key-value dictioneries that map types to object it looks like:
dic.Add(object value)
and T is not necessarily the type of the value... a lot of times it isn't...
I know it's written poorly, but i can't fix it...
I can work around it, but only at runtime...
I already did it with reflections, but if there's a better way to do it without them i would be happy to learn...
Thank you
This is a bit of a hack but you can get dynamic to do the reflection work for you by something like,
class Program
{
static void Main(string[] args)
{
var b = 6;
var t = (dynamic)new T();
var n = t.Foo(b);
}
class T
{
public string Foo<T>(T a)
{
return typeof(T).Name;
}
}
}
Here the dynamic call will extract the type of b and use it as a type parameter for Foo().
You can use dynamic keyword if you're using .NET 4. In a word, the type of the variable will be resolved at run time so it is a super generic type ;) You can read a article here or read the MSDN documentation
Saly refelction is THE solution to the problem, whether it is nice or not is irrelevant here. It is the runtime designed mechanism to achieve exactly this. As there is no parameter or generics to use as input, this is the only way to do it - it is also senseless. As in: your example is bad. Because in the example the type is hardcoded.
If the method where b exists has b as generic parameter, the type is available for passing to foo. If not - reflection is THE way to go, albeit the syntax looks clumsy. Only one time, though.
This I believe is the only way:
var foo = typeof(Foo<>).MakeGenericType(typeof (bar));
You can set up a class which takes a type parameter at run time which can be used in the methods in that class.
public class GenericClass<T>()
{
ICommonInterface TheObject;
public GenericClass(T theObject)
{
TheObject = theObject;
}
public string GetName()
{
return TheObject.Name;
}
}
But this is only really useful if the Types being passed in share interfaces so have common properties between them. In your example it seems that relection is the answer as depending on the type you want to access specific properties.