0

我想知道是否可以通过字符串调用动态 c# 对象上的函数。我想做这样的事情:

string lMethodName = "MethodName";
dynamic lDynamicObject = GetDynamicObject();
lDynamicObject.Invoke(lMethodName, lParameters);

任何想法或解决方案将不胜感激。

也许就像 Servy 所说的,有一种更好的方法可以通过不同的设计来实现我们想要的。我们正在使用 SignalR 并有一个仪表板 Web 应用程序。我们希望仪表板中的每个小部件都能够将数据推送到它。为了实现这一点,我们将使用剃须刀代码将小部件 ID 注入到每个单独的小部件 SignalR 客户端代理中。每个小部件都将具有以下内容:

hub.client.updateWidget123456 = aUpdateFunction;

其中 123456 是小部件的 ID。在服务器端 SignalR 集线器代码上,我们可以回调客户端 javascript 函数:

int lWidgetId = 123456;
dynamic lDynamic = Clients.All;
lDynamic.Invoke("updateWidget" + lWidgetId, lParameters);

在不创建 javascript 代理方法的情况下,我可以想到其他方法来实现这一点。我认为这很好,因为服务器与每个单独的小部件都有直接的通信线路。可以从多个仪表板/浏览器访问它们,但它们都将通过上面的单个调用进行更新。

我们可以通过在我们的 javascript 客户端代码中调用其他对象来实现这一点,这些对象知道所有小部件以及如何将信息定向到它们。我觉得这违背了 SignalR 的集线器架构,就像我们这样做是在重新发明轮子。

有人对更好的设计方法有任何想法吗?感谢您的帮助,感谢您的评论 Servy 引发了这次讨论。

另外,这个问题不是重复的。另一个问题与 Paul 在下面评论的动态对象无关。

4

4 回答 4

2

dynamic如果你知道它是一个普通的 C# 对象(即没有特殊的运行时绑定器),你只能使用反射来调用一个方法。

考虑以下实现可动态使用的属性包的类:

public class PropertyBag : DynamicObject
{
    private Dictionary<string, object> _propertyBag = new Dictionary<string, object>();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return _propertyBag.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        _propertyBag[binder.Name] = value;
        return true;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return base.GetDynamicMemberNames();
    }
}

执行以下操作是完全有效的:

dynamic propertyBag = new PropertyBag();

propertyBag.Name = "stackoverflow";
propertyBag.Value = 42;

但是,如果您尝试获取PropertyInfo这些动态属性中的任何一个,它将失败,因为PropertyBag该类没有实现它们:

public static void SetProperty(dynamic propertyBag, string propertyName, object value)
{
    PropertyInfo property = propertyBag.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
    if (property == null)
    {
        throw new NotImplementedException();
    }

    MethodInfo setProperty = property.GetSetMethod();
    setProperty.Invoke(propertyBag, new object[] { value });
}

这将引发异常:

dynamic propertyBag = new PropertyBag();

propertyBag.Name = "stackoverflow;      // works as expected
SetProperty(propertyBag, "Value", 42);  // throws a NotImplementedException

我在这个例子中使用了属性,因为它们更容易实现,但显然同样适用于方法。这样做的原因是dynamic在运行时动态评估但反射只能反映在静态实现上。(类应该GetProperties返回什么属性PropertyBag?)

如果您使用dynamic普通的 C# 对象,反射将按预期工作,但如果您不知道您正在处理什么类型的运行时绑定器以及它是如何在内部实现的,则您不能依赖它。

于 2013-04-18T20:16:55.323 回答
1

通过反思,我认为您可以做类似的事情(如果它是私有的-> NonPublic)

MethodInfo dynMethod = this.GetType().GetMethod("MethodName" + itemType, BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });

只需使用接受 BindingFlags 的 GetMethod 的重载版本:

于 2013-04-18T18:43:40.280 回答
1

简短的回答,是的,你可以这样做:

        class MyClass { public void Action() { Console.WriteLine("Do action"); } }
        // ...
        dynamic instance = new MyClass();
        instance.GetType().GetMethod("Action").Invoke(instance, null);

但是在这种情况下,实例是动态类型这一事实绝对没有任何作用。你可以使用一个object类型,它会以同样的方式工作。链中的第一个方法,GetType() 返回typeof(MyClass),然后从那里开始就是普通的老式反射。

使用 dynamic 关键字你可以做到这一点,这更有趣,虽然在运行时不太灵活:

        dynamic instance = new MyClass();
        instance.Action();

这将使用反射在运行时查找操作。在此示例中,与在此处设置的情况dynamic有所不同并不是很明显,但是您可以使用第二行来执行任何名为 action 的方法,只要该实例具有具有该名称的方法即可。varMyClass

于 2013-04-18T18:56:46.307 回答
0

对的,这是可能的。您想要做的事情称为“反射”,并且可以在大多数高级语言中使用

这是C 中反射的示例。它实际上非常强大,可以让你的代码在一定程度上“意识到自己”

于 2013-04-18T18:44:56.630 回答