c#如何获取CallerMember的类型名称

Jua*_*mez 19 c#

我上了这堂课

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)

  • 我希望有一个 [CallerMemberType]!由于 StackTrace 方法由于内联而不稳定,而且它没有为 UWP 实现,这是我迄今为止发现的最好的方法。 (5认同)

Sté*_*hon 8

来电者

诚然,让呼叫者成员名称是在对象模型中没有“天然”。这就是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

而这正是您所得到的。


其他无法解决问题的情况,请提供解决方案。

尽管这完全可以满足您的要求,但在其他情况下,它还是行不通的。

  • 情况1:当调用方是静态方法时(没有“ this”)。
  • 情况2:当您想要调用方方法本身的类型,而不是调用方本身的类型时(可能是第一个的子类)。

在这些情况下,a [CallerMemberType]可能有意义,但是有更简单的解决方案。注意,静态调用者的情况更简单:没有对象,因此它与调用方法的类型之间没有差异。不fooBase,只有CustClass。

情况1:当调用方是静态方法时(不存在“ this”)

如果至少一个调用方是静态方法,则不要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],而是在所有呼叫站点中重复呼叫者姓名的问题。

情况2:当需要调用者方法的类型而不是调用者的类型时

例如,在类中,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] 完全避免重复可能仍然有意义,但是:

  • 添加到编译器中的任何东西都是维护成本的复杂性负担
  • 鉴于现有的解决方案,我对C#开发团队列表中的优先级较高的项目并不感到惊讶。


Nuc*_*ucS 6

请参阅编辑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]

编辑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)

使用这种方法来满足您的精确需求.

  • 走路时你需要非常小心.在进行优化时可以内联方法,从而导致类型错误. (3认同)