编程语言
首页 > 编程语言> > c# – 实例方法的’this’参数可以是无类型的(即System.Object)吗?

c# – 实例方法的’this’参数可以是无类型的(即System.Object)吗?

作者:互联网

我正在使用System.Reflection.Emit的TypeBuilder来发出一堆带有实例方法的自定义.NET类.例如:

public class EmittedClass
{
    public bool TryGetName(out string value)
    {
        ...
    }

    public bool TryGetAge(out int value)
    {
        ...
    }
}

所有方法都遵循可由通用委托描述的相同签名:

public delegate bool TryGetter<T>(out T value);

当然,我希望能够在调用站点上显式指定目标实例,如下所示:

var instance = InstanceFactory.CreateInstance();
var tryGetName = InstanceFactory.CreateTryGetter<string>("Name");
string name;
if (tryGetName(instance, out name)) // Problem here.
{
    ...
}

为此,我需要将委托变成一个所谓的开放委托:

public delegate bool TryGetter<T>(object instance, out T value);

由于我没有目标实例的编译时类型,我需要将其作为System.Object传递.但是,这会在运行时中断,因为实例方法期望其“this”属于声明类的类型.哎哟.

我目前使用的解决方案是创建一个中间lambda表达式,它接受输入对象,执行运行时强制转换为目标类型,然后继续调用目标方法.它有效,但我觉得在中间有这个kludge感到不安.

问题是:我可以以某种方式更改我发出的方法,以便他们的这个参数将接受任何System.Object并仍然保持我的发出代码可验证?

如果没有,我想我仍然可以通过使方法静态并在其体中执行转换来避免中间lambda.然而,理想情况下,我想完全避免投射,但我怀疑由于CIL验证和元数据加载的工作方式,这在受管理的世界中无法忍受.

只是想知道是否有更多了解CIL的人可以就这个问题给我建议.谢谢!

更新:我正在努力解决的问题

类具有属性,通常由字段支持.如果期望所述类的实例一次仅维持单个状态,则这很好.对于状态,我指的是在给定时间实例字段中的值的组合.

我的业务需求是为普通字段实现替代存储,这将使单个类实例同时具有多个状态.此要求的一个目标是使其尽可能高效,包括访问的内存和速度.

我的方法背后的核心思想是使用System.Reflection.Emit创建业务类的镜像,并让业务类维护一组这些实例,每个实例对应一个给定的状态.然后,业务类的getter和setter自然必须连接到状态实例上的适当方法.涉及的细节更多,但这是核心理念.

我希望这个解释有助于理解我提出这个问题的原因.我很欣赏它似乎对许多人来说过度工程,但其他不涉及System.Reflection.Emit的替代方案只是过于缓慢和资源匮乏.我不能那样.

解决方法:

您不需要在委托签名中表示“this”类型.

这是一个委托定义,如下所示:

public delegate bool TryGetter<T>(out T value);

形式的任何变量:

TryGetter<T> x;

可以持有:

>类型R上的实例方法,带有签名bool Foo(out T value),以及类型为R的对象实例.
>带有签名静态bool Foo的静态方法(输出T值)
>给定类型为R的对象实例的带有签名静态bool Foo(R对象,out T值)的静态方法.

第三种形式称为委托currying,并允许具有N 1个参数的静态方法表现得好像它是具有N个参数的实例方法(但是只有第一个参数可以被curry).

所以,你想要的界面是:

var instance = InstanceFactory.CreateInstance();
var tryGetName = InstanceFactory.CreateTryGetter<string>(instance,"Name");

然后你可以这样做:tryGetName()返回值.

您可能想要使用案例#3,在其中使用签名bool TryGetWhatEver(TheTypeOfInstance obj,out WhatEver x)生成DynamicMethod,然后创建TryGetter< WhatEver>.

但是我仍然很好奇为什么你需要这样做.除非你动态生成应用程序的大块(如rails),否则这看起来会过于复杂.

标签:c,cil,reflection-emit
来源: https://codeday.me/bug/20190621/1255060.html