如果Type可以支持接口,解决的最佳方法是什么? (鸭打字)

时间:2010-11-23 17:23:31

标签: c# reflection.emit duck-typing

我正在使用Reflection.Emit在运行时构建一个类型。最终用户提供基本类型,以及新类型应支持的接口。如果接口具有base-type不支持的成员,我创建一个stub方法来调用存储在静态字段上的委托(我只支持具有15个或更少参数的非泛型方法,没有ref或out参数,因为这是我当前的要求。请不要提出这个限制的问题。委托采用baseType的第一个参数),用户可以在尝试构造类型之前提供。

但是,我想避免为可以通过类型满足的接口成员创建委托存根。例如

public class Goose
{
     public void Quack()
     {
       // quack implementation details go here.
     }
}

public interface IDuck
{
     void Quack()
}

我希望如果您将Goose new[]{typeof(IDuck)}发送到我的构建器,我将不会为void Quack()创建存根,因为goose满足接口。

接口映射不起作用,因为Goose没有实现IDuck,我不能要求新构建的接口映射类型,因为TypeBuilder不支持需要构造的类型

如何以远程高效的方式解决此问题?我只需要调查公开可见的成员,如果一个类型实现了一个具有相同方法的接口,我可以假设它不应该用作目标。 (例如,如果Goose实施void IGoose.Quack(),则不应将其视为void IDuck.Quack()的目标。 (无论如何,BindingFlags.Public | BindingFlags.Instance应该能够过滤掉这些元素。

2 个答案:

答案 0 :(得分:0)

你应该通过反射到一个哈希集中获得所有基类型公共实现成员(MemberInfo实现GetHashCode我不知道它是否可以比较不同类型的成员,你可能需要你的哈希对象来匹配签名类型和name),然后当你循环遍历新接口的成员时,如果在hashset中不存在,你只生成你的存根代码。

在成员存在之前声明TypeBuilder上的接口并不是问题,只要你不在它们之前调用CreateType并且你不应该关心基类型实现的其他接口,因为你只关心它关于与您的新界面匹配的成员的签名。

只要你通过interface& amp缓存结果类型,它在所有性能方面都不应该是坏的。基础类型。

答案 1 :(得分:0)

这实际上是一个以有效的方式比较MemberInfos的名称和签名的问题。您可以通过调用MemberInfo上的ToString来获取包含成员的名称和签名的字符串。此字符串可用于确定两个成员是否等同于签名。如果将字符串放入HashSet,则比较效率非常高。

ToString构建类似的签名字符串的事实在内部由.NET框架用于序列化和反序列化MemberInfo个对象,但是,AFAIK,实际上没有记录。因此,如果您不想依赖此未记录的行为,则可以构建自己的签名字符串并进行比较。但是,请注意,一旦考虑了泛型类型参数,这可能会变得非常复杂。