我正在使用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
应该能够过滤掉这些元素。
答案 0 :(得分:0)
你应该通过反射到一个哈希集中获得所有基类型公共实现成员(MemberInfo实现GetHashCode我不知道它是否可以比较不同类型的成员,你可能需要你的哈希对象来匹配签名类型和name),然后当你循环遍历新接口的成员时,如果在hashset中不存在,你只生成你的存根代码。
在成员存在之前声明TypeBuilder上的接口并不是问题,只要你不在它们之前调用CreateType并且你不应该关心基类型实现的其他接口,因为你只关心它关于与您的新界面匹配的成员的签名。
只要你通过interface& amp缓存结果类型,它在所有性能方面都不应该是坏的。基础类型。
答案 1 :(得分:0)
这实际上是一个以有效的方式比较MemberInfos
的名称和签名的问题。您可以通过调用MemberInfo上的ToString
来获取包含成员的名称和签名的字符串。此字符串可用于确定两个成员是否等同于签名。如果将字符串放入HashSet
,则比较效率非常高。
ToString
构建类似的签名字符串的事实在内部由.NET框架用于序列化和反序列化MemberInfo
个对象,但是,AFAIK,实际上没有记录。因此,如果您不想依赖此未记录的行为,则可以构建自己的签名字符串并进行比较。但是,请注意,一旦考虑了泛型类型参数,这可能会变得非常复杂。