我使用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"
}
}
一个尴尬的解决方案:
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;
我能想到的唯一解决方案(类似于你不那么尴尬的解决方案)。
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;
}
最后我使用了下面的代码:
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;
我认为你被困在枚举接口;我还没有看到访问特定接口的方法。
此外,如果显式实现接口,可能会出现一个小的边缘情况。在这种情况下(void ISample.Do()
) MethodBase。名称将是完全限定的方法名称(例如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属性区分。
。public void Do()
有IsHideBySig和IsPublic设置为true,而void ISample.Do()
有IsFinal, IsVirtual, IsPrivate, IsHideBySig都设置为true。但我不确定这对所有情况都足够。