0

Unity をインターセプトに使用しています。私は多くのインターフェースを持っているので、VirtualMethodInterceptor. 私の行動では、呼び出されたメソッドが特定のタイプのインターフェイスで(特別な属性で)宣言された場合にのみ反応したいと思います。私は MethodBase.DeclaringType が私の問題を解決すると思っていましたが、私が望んでいたものとは異なる動作をします。実装タイプを返します。

メソッドは複数のインターフェイスで宣言できるため、理にかなっていることに同意できますが、それらのリストを簡単に取得する方法が必要です。残念ながらまだ見つかっていません。

私の問題を示す小さなサンプル

public interface ISample
{
    void Do();
}

public class Sample : ISample
{
    public void Do()
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        var m = typeof(Sample).GetMethod("Do") as MethodBase;
        Console.WriteLine(m.DeclaringType.Name); // Prints "Sample"
    }
}

1つの厄介な解決策:

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces()
                where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0
                where i.GetMethod(input.MethodBase.Name, input.MethodBase.GetParameters().Select(p=>p.ParameterType).ToArray()) != null
                select i;
4

3 に答える 3

0

私はあなたがインターフェースを列挙することに固執していると思います。特定のインターフェースにアクセスする方法を見たことがありません。

また、インターフェイスが明示的に実装されている場合に発生する可能性のある小さなエッジケースがあります。その場合、(void ISample.Do())MethodBase.Nameは、完全修飾されたメソッド名(eg MyApp.ISample.Do)であり、ではありませんDo

私が見つけた唯一の解決策は、主要な情報を取り除くことでした。例えば

string methodName = input.MethodBase.Name;
int methodIndex = methodName.LastIndexOf('.');

if (methodIndex != -1)
{
    methodName = methodName.Substring(methodIndex + 1, 
        methodName.Length - methodIndex - 1);
}

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces()
                 let parameters = input.MethodBase.GetParameters().
                     Select(p => p.ParameterType).ToArray()
                 where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0
                 where i.GetMethod(methodName, parameters) != null
                 select i;

また、同じ名前と署名を持つ別のメソッドがある場合、そのメソッドがパブリックメソッドではなくインターフェイスを介して呼び出されたかどうかを判断する方法がわかりません。

public class Sample : ISample
{
    public void Do()
    {
        // this is a public method
    }

    void ISample.Do()
    {
        // this is the interface implementation
    }
}

同じ名前と署名を持つ他のメソッドを探し、他のMethodBaseプロパティを調べることで区別できる可能性があると思います。

つまり、IsHideBySigとIsPublicpublic void Do()がtrueに設定されvoid ISample.Do()、IsFinal、IsVirtual、IsPrivate、IsHideBySigがすべてtrueに設定されています。しかし、それがすべてのシナリオに十分かどうかはわかりません。

于 2011-10-03T16:28:09.373 に答える
0

私が思いついた唯一の解決策です(ただし、それほど厄介な解決策と同様です)。

public static bool IsMethodDeclaredInInterface(MethodBase method, Type myInterface)
{
    var methodType = method.DeclaringType;
    var typeFilter = new TypeFilter((t, crit) =>
                                        {
                                            var critTypes = crit as Type[];
                                            return critTypes != null && critTypes.Any(ty => ty.FullName == t.FullName);
                                        });
    var res = methodType.FindInterfaces(typeFilter, new[] {myInterface});
    return res.Length > 0;
}
于 2011-09-30T11:16:59.100 に答える
0

最終的に私はこのコードを使用しました:

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces()
                 let parameters = input.MethodBase.GetParameters().Select(p=>p.ParameterType).ToArray()
                 where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0
                 where i.GetMethod(input.MethodBase.Name, parameters) != null
                 select i;
于 2011-10-03T09:42:27.393 に答える