【问题标题】:C# Converting a DynamicObject to arbitrary typeC# 将 DynamicObject 转换为任意类型
【发布时间】:2011-03-28 22:10:55
【问题描述】:

我正在编写一个 Javascript C# 桥并遇到以下问题:

有一个类 JSObject:

public class JSObject : DynamicObject
{
    public JSEngineAPI wrappedObject { get; set; }

    public JSObject(JSEngineAPI WrappedObject);
    public override bool TryConvert(ConvertBinder binder, out object result);
    public override bool TryGetMember(GetMemberBinder binder, out object result);
    ...
}

让我们假设有一个简单的测试用例,比如

public class TestClass
{
    public string message = "This is a C# string";
}

public class TestApp
{
    public string testComplexObject(TestClass obj)
    {
        return obj.message;
    }
}

现在我希望能够做到

JSObject jsObj = ...;
string message = testComplexObject(jsObj);

执行obj.message 应该执行TryGetMember() 调用。实际上,jsObj 应该伪装成一个 TestClass 实例。注意 testComplexObject 的调用只是一个例子,以后我需要能够支持调用任意参数的任意函数。

我尝试了各种方法来完成这项工作,但都没有奏效。所以我想知道实现这一目标的好方法。

我考虑过在运行时创建一个继承自TestClass 的类。这个动态类将包含生成的成员,这些成员重载了它们的基类挂件。这些方法中的每一个都将转发到 JSObject/JSEngineAPI 以执行实际工作。然后我可以将这个动态类的一个实例传递给 testComplexObject 方法。

但这听起来相当复杂,我很想知道是否有更简单/其他的方法。

编辑#1:我猜如果你去掉“DynamicObject”部分,这个问题有点像如何在运行时为类型 T 创建代理?

编辑#2:我现在也研究了 RealProxy 和 IDynamicMetaObjectProvider,想知道这些是否有帮助。

感谢您的宝贵时间, -马蒂亚斯

【问题讨论】:

  • 据我所知,将动态对象视为不同类型对象的实例是不可能的,您需要执行转换或使包装对象派生自目标类型。您是否考虑过让该方法取而代之的是接​​口?然后你的动态对象可以只实现接口,你可以做你的操作。或者甚至只是让它成为动态的,然后它会在你实现它们时使用正确的方法。
  • 感谢您的评论,杰夫。我不能让它带一个接口。基本上,我的桥旨在将任意 C# 库暴露给 javascript。不幸的是,这些 C# 库将不限于接口类型的参数和对象。如果 C# 有多重继承,我可能会从 DynamicObject 和 TestClass 继承。
  • 如何设置参数dynamic,然后它会起作用,您仍然可以传递TestClass 的实际实例。
  • @Jeff M:我根本无法更改 testComplexObject 方法的签名。这是我要调用的任意 C# 函数的示例。

标签: c# .net dynamic dynamicobject


【解决方案1】:

由于方法的签名不能更改,您可以创建一个代理来代替您的动态对象。仅当对象是 POD 或您坚持可以覆盖的虚拟方法时,这才会有效。否则你的方法可能最终不会被使用。它将实现所需的类型,但会将所有访问权限传递给您的实际对象。如果您向动态对象添加一些转换方法,使用它会很容易。像这样的:

public class JSObject : DynamicObject
{
    class TestClassProxy : TestClass
    {
        private dynamic wrapper;
        public TestClassProxy(dynamic obj)
        {
            wrapper = obj;
            // assign copies of the fields
            message = obj.message;
        }
        // override all required methods and properties
        public override void SampleMethod()
        {
            wrapper.SampleMethod();
        }
        public override int SomeValue
        {
            get { return wrapper.SomeValue; }
            set { wrapper.SomeValue = value; }
        }
        // etc...
    }

    public override bool TryConvert(ConvertBinder binder, out object result)
    {
        if (binder.Type == typeof(TestClass))
        {
            result = new TestClassProxy(this);
            return true;
        }
        // your other conversions
        return base.TryConvert(binder, out result);
    }
    // etc...
}

如果你需要对你的对象做更多的事情,我不知道除了改变方法的签名之外你还能怎么解决这个问题。

【讨论】:

  • 感谢您的时间和回答,杰夫。我已将其标记为已接受,希望您没问题。
猜你喜欢
  • 2023-03-17
  • 2017-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多