C# 将 DynamicObject 转换为任意类型

发布于 2024-10-27 15:40:56 字数 1361 浏览 0 评论 0原文

我正在写一个 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,想知道它们是否有任何帮助。

感谢您抽出时间, ——马蒂亚斯

I'm writing a Javascript <-> C# bridge and ran into the following problem:

There's a class 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);
    ...
}

and let's assume there's a simple test case like

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

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

Now I want to be able to do

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

Doing obj.message should perform a TryGetMember() call. Effectively the jsObj should pretend to be a TestClass instance. Note that the call to testComplexObject is just an example, later I need to be able to support calling arbitrary functions with arbitrary arguments.

I've tried various ways to make this work, but none of them worked. So I wonder about a good way to achieve this.

I've thought about creating a class at runtime which inherits from TestClass. This dynamic class will contain generated members which overload their base class pendants. Each of these methods would forward to the JSObject/JSEngineAPI to perform the real work. Then I could pass an instance of this dynamic class into the testComplexObject method.

However this sounds rather involved and I'd love to know if there are easier/other approaches to this.

EDIT #1: I guess if you take away the "DynamicObject" part this question is a bit like how can I create a proxy for type T at runtime?

EDIT #2: I've also looked into RealProxy and IDynamicMetaObjectProvider now and wonder if these are of any help.

Thanks for your time,
-Matthias

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

银河中√捞星星 2024-11-03 15:40:56

由于方法的签名无法更改,因此您可以创建一个代理来代替动态对象。仅当对象是 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...
}

如果您需要对对象执行更多操作,除了更改方法的签名之外,我不知道您还能如何解决此问题。

As the signature of the method cannot be changed, you could create a proxy to stand in for your dynamic object. This will be effective only if the objects are PODs or you stick to virtual methods that you could override. Otherwise your methods could end up not being used. It will implement the the desired type but will pass all accesses to your actual object. Using this will be easy if you add some conversion methods to your dynamic object. Something like this:

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...
}

If you need to do more with your objects, I don't know how else you could get around this other than changing the method's signature.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文