解决类型是否支持接口的最佳方法? (鸭子打字)

发布于 2024-10-04 00:25:01 字数 909 浏览 10 评论 0原文

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

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

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

public interface IDuck
{
     void Quack()
}

,如果您将 Goosenew[]{typeof(IDuck)} 发送给我的构建器,我将不会为 创建存根code>void Quack() 因为 goose 满足接口。

接口映射不起作用,因为 Goose 没有实现 IDuck,并且我无法向新构建的类型请求接口映射,因为 TypeBuilder 在需要构造的类型上不支持它。

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

I'm building a type at runtime using Reflection.Emit. An end user supplies the base-type, and what interfaces the new type should support. If the interface has members that the base-type cannot support, I create a stub method that calls a delegate stored on a static field (I only support non-generic methods with 15 or less parameters, without ref or out parameters as that's my current requirements. Please don't bring up issues with this limitation. The delegate takes a first parameter of baseType ), that the user can supply before trying to construct the type.

However, I'd like to avoid creating delegate stubs for interface members that can be satisfied by the type. e.g.

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

public interface IDuck
{
     void Quack()
}

I'd like that if you sent in Goose with new[]{typeof(IDuck)} here to my builder, I won't create a stub for the void Quack() as goose satisfies the interface.

The interface mapping doesn't work as Goose doesn't implement IDuck, and I can't ask the newly built type for the interface mapping as TypeBuilder doesn't support it on types that need to be constructed.

How can I resolve this in a manner that is remotely efficient? I only must investigate publicly visible members, and if a type implements an interface explicitly that has the same method I can assume that it should not be used as the target. (e.g. if Goose implemented void IGoose.Quack() then it should not be considered a target for void IDuck.Quack()). (Anyway, BindingFlags.Public | BindingFlags.Instance should be suffecient to filter these elements out).

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

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

发布评论

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

评论(2

心碎的声音 2024-10-11 00:25:01

您应该通过反射到哈希集来获取所有基本类型公共实现的成员(MemberInfo 确实实现了 GetHashCode 我不知道它是否可以比较不同类型的成员,您可能需要哈希对象来匹配签名类型和名称),然后,当您循环访问新接口的成员时,如果哈希集中不存在,则仅生成存根代码。

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

只要您通过接口和接口缓存结果类型,它的性能就不应该很差。基础类型。

You should get all the base type public implemented members via reflection into a hashset (MemberInfo does implement GetHashCode I don't know if it will work comparing members on different types you may need your hash object to match up just signature types and name), then when you are looping through the the new interface's members you only generate your stub code if it doesn't exist in the hashset.

It's not a problem to declare the interface on a TypeBuilder before the members are there as long as you don't call CreateType until they are there and you shouldn't care what other interfaces that the base type implements as you only care about the signature of the members matching up with your new interface.

It shouldn't be bad at all performance wise as long as you cache the resulting type by interface & base type.

殤城〤 2024-10-11 00:25:01

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

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

This is effectively a question of comparing the names and signatures of MemberInfos in an efficient way. You can get a string that contains the name and signature of a member by calling ToString on the MemberInfo. This string can be used to determine whether two members are signature-equivalent. If you put the strings into a HashSet, the comparison will be quite efficient.

The fact that ToStringbuilds a comparable signature string is used by the .NET framework internally for serializing and deserializing MemberInfo objects, however, AFAIK, this is not actually documented. Therefore, if you don't want to rely on this undocumented behavior, you could build your own signature strings and compare them. However, be aware that this can become quite complex once you take generic type parameters into account.

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