c#如何获取CallerMember的类型名称
我上了这堂课
public class fooBase { public List MethodsList; public bool fooMethod([CallerMemberName]string membername ="")) { //This returns a value depending of type and method } public void GetMethods() { // Here populate MethodsList using reflection } }
而这个属性类
// This attribute get from a database some things, then fooMethod check this attribute members public class CustomAttribute { public string fullMethodPath; public bool someThing ; public bool CustomAttribute([CallerMemberName]string membername ="") { fullMethodPath = **DerivedType** + membername // I need here to get the type of membername parent. // Here I want to get CustClass, not fooBase } }
然后我有这个
public class CustClass : fooBase { [CustomAttribute()] public string method1() { if (fooMethod()) { .... } } }
我需要CallerMember的Type名称,有类似[CallerMemberName]的东西来获取Caller的类所有者?
它并非万无一失,但.NET的约定是每个文件有一种类型,并且命名文件与类型相同。 我们的工具也倾向于强制执行此约定,即Resharper和Visual Studio。
因此,从文件路径推断类型名称应该是合理的。
public class MyClass { public void MyMethod([CallerFilePath]string callerFilePath = null, [CallerMemberName]string callerMemberName = null) { var callerTypeName = Path.GetFileNameWithoutExtension(callerFilePath); Console.WriteLine(callerTypeName); Console.WriteLine(callerMemberName); } }
在我看来,CompilerServices提供的信息太少,无法从调用方法中获取类型。 你可以做的是使用StackTrace
( 请参阅 StackTrace
)查找调用方法(使用GetMethod()
)并从那里使用Reflection
获取类型。
考虑以下:
using System.Runtime.CompilerServices; public class Foo { public void Main() { what(); } public void what() { Bar.GetCallersType(); } public static class Bar { [MethodImpl(MethodImplOptions.NoInlining)] //This will prevent inlining by the complier. public static void GetCallersType() { StackTrace stackTrace = new StackTrace(1, false); //Captures 1 frame, false for not collecting information about the file var type = stackTrace.GetFrame(1).GetMethod().DeclaringType; //this will provide you typeof(Foo); } } }
注意 –正如@Jay在评论中所说的那样,它可能相当昂贵,但它确实很有效。
编辑:
我发现了几个比较性能的arcticle,与Reflection
相比,它确实是非常昂贵的,而Reflection
也被认为不是最好的。
见: [1] [2]
编辑2:
因此,在深入研究StackTrace
,使用它确实不安全甚至是昂贵的。
由于将调用的每个方法都将使用[CustomAttribute()]
标记,因此可以在静态列表中收集包含它的所有方法。
public class CustomAttribute : Attribute { public static List MethodsList = new List (); static CustomAttribute() { var methods = Assembly.GetExecutingAssembly() //Use .GetCallingAssembly() if this method is in a library, or even both .GetTypes() .SelectMany(t => t.GetMethods()) .Where(m => m.GetCustomAttributes(typeof(CustomAttribute), false).Length > 0) .ToArray(); MethodsList = new List (methods); } public string fullMethodPath; public bool someThing; public CustomAttribute([CallerMemberName] string membername = "") { var method = MethodsList.FirstOrDefault(m=>m.Name == membername); if (method == null || method.DeclaringType == null) return; //Not suppose to happen, but safety comes first fullMethodPath = method.DeclaringType.Name + membername; //Work it around any way you want it // I need here to get the type of membername parent. // Here I want to get CustClass, not fooBase } }
使用这种方法来满足您的精确需求。
来电成员
当然,获取调用者成员名称在对象模型中不是“自然的”。 这就是C#工程师在编译器中引入CallerMemberName的原因。
真正的敌人是重复,基于堆栈的解决方法是低效的。
[CallerMemberName]
允许获取信息而不会重复,也不会产生不良影响。
来电者类型
但是获取调用者成员类型 是自然的,并且很容易获得而无需重复。
怎么做
在fooMethod
添加“caller”参数,不需要特殊属性。
public bool fooMethod(object caller, [CallerMemberName]string membername = "") { Type callerType = caller.GetType(); //This returns a value depending of type and method return true; }
并称之为:
fooMethod(this);
这回答了这个问题
你说
//这里我想获得CustClass,而不是fooBase
而这正是你将得到的。
其他不会炒的情况。
虽然这完全符合您的要求,但还有其他不同的情况,它不起作用。
- 当调用者是静态方法时(没有“this”)。
- 当一个人想要调用者方法本身的类型,而不是调用者本身的类型(可能是第一个的子类)。
在这些情况下, [CallerMemberType]
可能有意义。 然而,这些案例的解决方案主要是调用者源文件的本地解决方案,因此它们并不是一个大问题恕我直言。