开发者

Best way to resolve if a Type could support an interface? (Duck-Typing)

开发者 https://www.devze.com 2023-01-26 19:10 出处:网络
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 suppo

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开发者_Python百科 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).


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消