我上了这堂课
public class fooBase
{
public List<MethodsWithCustAttribute> MethodsList;
public bool fooMethod([CallerMemberName]string membername =""))
{
//This returns a value depending of type and method
}
public void GetMethods()
{
// Here populate MethodsList using reflection
}
}
Run Code Online (Sandbox Code Playgroud)
而这个属性类
// 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
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有这个
public class CustClass : fooBase
{
[CustomAttribute()]
public string method1()
{
if (fooMethod())
{
....
}
}
}
Run Code Online (Sandbox Code Playgroud)
我需要CallerMember的Type名称,有类似[CallerMemberName]的东西来获取Caller的类所有者?
Pau*_*aul 16
它不是万无一失的,但.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);
}
}
Run Code Online (Sandbox Code Playgroud)
诚然,让呼叫者成员名称是在对象模型中没有“天然”。这就是C#工程师在编译器中引入CallerMemberName的原因。
真正的敌人是复制,而基于堆栈的解决方法效率低下。
[CallerMemberName] 允许获取信息而无需重复且没有不良影响。
但是获取主叫方成员类型 是自然的,并且无需重复即可轻松获得。
将“呼叫者”参数添加到fooMethod,无需特殊属性。
public bool fooMethod(object caller, [CallerMemberName]string membername = "")
{
Type callerType = caller.GetType();
//This returns a value depending of type and method
return true;
}
Run Code Online (Sandbox Code Playgroud)
并这样称呼它:
fooMethod(this);
Run Code Online (Sandbox Code Playgroud)
你说过
//在这里我要获取CustClass,而不是fooBase
而这正是您所得到的。
尽管这完全可以满足您的要求,但在其他情况下,它还是行不通的。
在这些情况下,a [CallerMemberType]可能有意义,但是有更简单的解决方案。注意,静态调用者的情况更简单:没有对象,因此它与调用方法的类型之间没有差异。不fooBase,只有CustClass。
如果至少一个调用方是静态方法,则不要GetType()在方法内部进行操作,而应在调用站点上进行操作,因此不要将“ this”传递给方法,而应传递类型:
public bool fooMethodForStaticCaller(Type callerType, [CallerMemberName]string membername = "")
Run Code Online (Sandbox Code Playgroud)
静态调用者将执行以下操作:
public class MyClassWithAStaticMethod // can be CustClass, too
{
public static string method1static()
{
fooMethodForStaticCaller(typeof(MyClassWithAStaticMethod));
}
}
Run Code Online (Sandbox Code Playgroud)
为了保持与对象调用者的兼容性,请保留另一个fooMethod使用该this指针的对象,或者可以将其删除,对象调用者将这样做:
fooMethod(this.GetType());
Run Code Online (Sandbox Code Playgroud)
您会注意到typeof(MyClassWithAStaticMethod)上面的重复了类名,这是真的。最好不要重复类名,但这没什么大不了的,因为它只重复一次,作为键入的项(不是字符串)并在同一个类内。它不像要解决的原始问题那样严重[CallerMemberName],而是在所有呼叫站点中重复呼叫者姓名的问题。
例如,在类中,fooBase您想anotherFooMethod从对象上下文中调用,但希望传递的类型始终为fooBase,而不是对象的实际类型(例如CustClass)。
在这种情况下,有一个this指针,但是您不想使用它。因此,只需使用实际上相同的解决方案:
public class fooBase
{
[CustomAttribute()]
public string method1()
{
if (anotherFooMethod(typeof(fooBase)))
{
....
}
}
}
Run Code Online (Sandbox Code Playgroud)
就像在情况1中一样,除非您之前存在猖code的代码重复问题,否则每个呼叫站点都重复一次,在这种情况下,这里要解决的问题不是您应该担心的问题。
[CallerMemberType] 完全避免重复可能仍然有意义,但是:
请参阅编辑2以获得更好的解决方案
CompilerServices在我看来,提供的信息太少,无法从调用方法中获取类型.你可以做的是使用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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意 -正如@Jay在评论中所说的那样,它可能相当昂贵,但它确实做得很好.
我找到了几个比较性能的arcticle,它确实非常昂贵,相比之下,Reflection它也被认为不是最好的.
见:[1] [2]
因此,经过深入研究StackTrace,使用它确实是不安全的,甚至是昂贵的.
由于将要调用的每个方法都将标记为a [CustomAttribute()],因此可以在静态列表中收集包含它的所有方法.
public class CustomAttribute : Attribute {
public static List<MethodInfo> MethodsList = new List<MethodInfo>();
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)
.ToList();
MethodsList = 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
}
}
Run Code Online (Sandbox Code Playgroud)
使用这种方法来满足您的精确需求.