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);
Related
Using dynamic pattern perhaps? You can call any method/property using the dynamic keyword, right? How to check whether the method exist before calling myDynamicObject.DoStuff(), for example?
You could write something like that :
public static bool HasMethod(this object objectToCheck, string methodName)
{
var type = objectToCheck.GetType();
return type.GetMethod(methodName) != null;
}
Edit : you can even do an extension method and use it like this
myObject.HasMethod("SomeMethod");
via Reflection
var property = object.GetType().GetProperty("YourProperty")
property.SetValue(object,some_value,null);
Similar is for methods
It is an old question, but I just ran into it.
Type.GetMethod(string name) will throw an AmbiguousMatchException if there is more than one method with that name, so we better handle that case
public static bool HasMethod(this object objectToCheck, string methodName)
{
try
{
var type = objectToCheck.GetType();
return type.GetMethod(methodName) != null;
}
catch(AmbiguousMatchException)
{
// ambiguous means there is more than one result,
// which means: a method with that name does exist
return true;
}
}
Wouldn't it be better to not use any dynamic types for this, and let your class implement an interface.
Then, you can check at runtime wether an object implements that interface, and thus, has the expected method (or property).
public interface IMyInterface
{
void Somemethod();
}
IMyInterface x = anyObject as IMyInterface;
if( x != null )
{
x.Somemethod();
}
I think this is the only correct way.
The thing you're referring to is duck-typing, which is useful in scenarios where you already know that the object has the method, but the compiler cannot check for that.
This is useful in COM interop scenarios for instance. (check this article)
If you want to combine duck-typing with reflection for instance, then I think you're missing the goal of duck-typing.
To avoid AmbiguousMatchException, I would rather say
objectToCheck.GetType().GetMethods().Count(m => m.Name == method) > 0
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.
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 create an object using this syntax:
var newMessage = Activator.CreateInstance(client.Key);
It appears to create an object of the correct type and allows the object properties to be set. However when I pass the object to a method with signature:
public void Publish<T>(T messageBody)
The Type defined by T is object.
How do I get around this? I can't change the method signature - its from a library - and I need to be able to create objects at runtime without knowing their type beforehand.
UPDATED
The function I am trying to perform relates to sending(Publishing) messages. Ordinarily I would register a message Handler like:
RegisterHandler<MyMessage> (m => do something with message );
and could then call
Publish<MyMessage> (message)
which would eventually end up at the handler. This is cool and works fine.
What I am trying to do is insert an intermediary to act as an exchange and publish the message to multiple handlers. I know there are other things I could use to do this for me such as RabbitMQ, but I was hoping to be able to achieve it with just a small modification to the current code.
So I have a method that registers subscriptions:
public virtual void registerSubscription<T1,T2>()
{
if (handlerMap.ContainsKey(typeof(T2)))
{
throw new ArgumentException("Message handler has already been registered for type: " +typeof(T2).Name);
}
if (!handlerMap.ContainsValue(typeof(T1)))
{
mqHost.RegisterHandler<T1> (m => distributeMessage(m) );
}
handlerMap[typeof(T2)] = typeof(T1);
}
I call the method with two classes, a base class and a class that inherits the base class:
public class MyMessage
{
public string name {get;set;}
}
public class MyMessage2:MyMessage{}
This bit works well and I get a map of handlers built up. The problem comes when I do the next bit, the distributeMessage method.
var match = handlerMap.Where(i => i.Value == message.Body.GetType());
foreach (var client in match)
{
var newMessage = Activator.CreateInstance(client.Key);
newMessage.PopulateWith(message.Body);
messageProducer.Publish(createMessage(newMessage));
}
The messageProducer.publish has the signature:
public void Publish<T>(T messageBody)
I can't (easily) modify this - it is part of a library. There is another method I could call:
public void Publish<T>(IMessage<T> message)
But I can't see that this would be any easier as I would have to create a Message which still requires .
You can use some reflection to try to create a generic method of Publish given the type information you knew when calling the Activator. If I have misunderstood what you are trying to do, please ask and I can modify this code.
object newObject = Activator.CreateInstance(myType);
var publishMethod = typeof(MessageProducer).GetMethod("Publish");
var publishMethodWithCorrectType = publishMethod.MakeGenericMethod(new Type[] { myType });
publishMethodWithCorrectType.Invoke(messageProducer, new object[]{newObject});
I hope this helps.
Try do this:
var newMessage = (MyType)Activator.CreateInstance(client.Key);
p.s. MyType is an base type or interface...
You would need to invoke the Publish<T> method via reflection as well to continue along this route.
Another suggestion would be to make the class object's class generic based on the client.Key type, then implement a Publish method within that class - the implementation will know what T is.
Found this answer to another question
and implemented this:
typeof(MessageExchange)
.GetMethod("createMessage",BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(newMessage.GetType())
.Invoke(null, new object[] { newMessage });
I'm now getting the correct type being passed through.
Is there a way to get a method's name (as a string) by providing the method itself?
class Person
{
bool Eat(Food food){...}
}
I want to somehow get the string "Eat". That's all! This can either be from an instance or from the class declaration using reflection.
My attempt:
public delegate bool EatDelegate(Food f);
EatDelegate eatDel = new EatDelegate(_person1.Eat);
string methodName = eatDel.GetInvocationList()[0].Method.Name;
This requires to know the method's delegate and the whole thing is unreadable
I want the methodName in order to dynamically invoke it.
Notes:
There is a delegate declaration for every method I want to invoke
I want to avoid specifying the method's name in order to avoid errors after reflection etc
The method isn't called the moment I want to get its name. (cannot use MethodBase.GetCurrentMethod() )
I have to use .Net 3.5
public string GetName(Expression<Action> exp)
{
var mce = exp.Body as MethodCallExpression;
return mce.Method.Name;
}
--
a Method
public int MyMethod(int i)
{
return 0;
}
and usage
var s= GetName(()=>this.MyMethod(0));
var methods = typeof(Person).GetMethods();
foreach (var method in methods)
{
if (method.Name.Equals("Eat"))
{
// do something here...
}
}