是否可以反映调用堆栈中的显式接口实现?我想使用此信息在界面本身上查找属性。
鉴于此代码:
interface IFoo
{
void Test();
}
class Foo : IFoo
{
void IFoo.Test() { Program.Trace(); }
}
class Program
{
static void Main(string[] args)
{
IFoo f = new Foo();
f.Test();
}
public static void Trace()
{
var method = new StackTrace(1, false).GetFrame(0).GetMethod();
// method.???
}
}
具体来说,在Trace()中,我希望能够从typeof(IFoo)
转到method
。
在观察窗口中,如果我查看method.ToString()
,它会给我Void InterfaceReflection.IFoo.Test()
(InterfaceReflection是我的程序集的名称)。
如何从那里到达typeof(IFoo)
?我必须从程序集本身使用基于名称的类型查找,还是Type IFoo
中某处隐藏了MethodBase
?
更新
这是最终解决方案,感谢Kyte
public static void Trace()
{
var method = new StackTrace(1, false).GetFrame(0).GetMethod();
var parts = method.Name.Split('.');
var iname = parts[parts.Length - 2];
var itype = method.DeclaringType.GetInterface(iname);
}
itype
将具有实现方法的接口类型。这只适用于显式接口实现,但这正是我需要的。现在我可以使用itype
来查询附加到实际接口类型的属性。
感谢大家的帮助。
答案 0 :(得分:3)
使用VS2010进行测试,我找到了DeclaringType,它获取包含该方法的对象类型,从中可以将接口作为Type对象。
public static void Trace() {
var stack = new StackTrace(1, true);
var frame = stack.GetFrame(0);
var method = frame.GetMethod();
var type = method.DeclaringType;
Console.WriteLine(type);
foreach (var i in type.GetInterfaces()) {
Console.WriteLine(i);
}
}
返回:
TestConsole.Foo
TestConsole.IFoo
(我称之为TestConsole项目)
答案 1 :(得分:2)
method
将是System.Reflection.RuntimeMethodInfo
,这是一个派生自System.Reflect.MethodBase
的类。你可以,例如在它上面调用Invoke()
(尽管如果你在获得它的时候这样做了,那么这将导致无限递归,最终因堆栈溢出而死亡)。
在其上调用ToString()
会返回一个完全限定的名称。你有没有把项目称为InterfaceReflection?
不确定你想要的更多。
编辑:好的,现在我做。要查找声明类型,请查看DeclaringType属性,这将返回声明方法的类(可以是调用它的类,或基类):
到目前为止很容易,这会为Foo返回一个Type对象。
现在对于棘手的一点,因为你关心它被声明的接口。但是,可能有多个接口定义了一个具有完全相同签名的方法,这意味着简单的问题“如果这来自一个接口,那个接口是什么?”并不总是有一个答案。
可能有一种更简洁的方法可以做到这一点,但我能想到的只是在你GetInterfaces()
的{{1}}对象上调用Type
,然后找一个名字的人匹配方法的签名。
答案 2 :(得分:0)
我不想过多假设,但在这种情况下,看起来你可能会引起一些混乱,因为Foo和Program是相互依赖的。通常情况下,我认为程序会“拥有”Foo(这将是程序的不可知),它负责设置委托,因此可以避免反思...你设置它的方式,Foo“拥有“(实际上,我认为取决于它可能更准确)程序的某种方式(因为它很难调用它的Program.Trace()),而程序”拥有“Foo的方式(因为它控制实例)。 / p>
我不知道这是否适用于您的特定场景,但看起来事件类型操作可能更有意义并且更简单地处理通信。
ETA:代码示例:
public interface IFoo
{
event EventHandler Testing;
void Test();
}
public class Foo : IFoo
{
public event EventHandler Testing;
protected void OnTesting(EventArgs e)
{
if (Testing != null)
Testing(this, e);
}
public void Test()
{
OnTesting(EventArgs.Empty);
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
IFoo f = new Foo();
f.Testing += new EventHandler(f_Testing);
f.Test();
}
static void f_Testing(object sender, EventArgs e)
{
IFoo foo = sender as IFoo;
if (foo != null)
{
//...
}
}
}
但是,我可能会误解你的问题。
答案 3 :(得分:0)
我认为.NET将全名附加到MethodInfo.Name属性的前面,以便它为每个方法都有一个唯一的名称。想一想:
interface IFoo
{
void Test();
}
interface IFoo2
{
void Test();
}
class Foo : IFoo, IFoo2
{
void IFoo.Test() { Trace(); }
void IFoo2.Test() { Trace(); }
}
在这种情况下,typeof(Foo).GetMethods()
会返回两个Test()
方法,但它们的名称会发生冲突,所以我猜它们会附加接口名称以使它们唯一?
MethodInfo.DeclaringType
返回包含实现的类型。因此,如果IFoo实际上是一些基类型而不是接口,并且那里有一个基本方法声明,那么.DeclaringType
将返回基类的类型。
有趣的是,我似乎无法在MethodInfo中的任何地方找到实际的接口名称,所以我想你必须按名称查找它,例如:
public static void Trace()
{
var method = new System.Diagnostics.StackTrace(1, false).GetFrame(0).GetMethod();
var fromType = method.DeclaringType;
if (method.Name.Contains("."))
{
var iname = method.Name.Substring(0, method.Name.LastIndexOf('.'));
fromType = Type.GetType(iname); // fromType is now IFoo.
}
}