How to use a variable as a method name using dynam

2019-02-09 14:11发布

问题:

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!)
    }

回答1:

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);
}


回答2:

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);
}


回答3:

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();
}


回答4:

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);


标签: c# signalr