一般获取当前类的名称?

Generically get the name of the current class?

提问人:Denis G. Labrecque 提问时间:8/25/2022 最后编辑:Denis G. Labrecque 更新时间:8/25/2022 访问量:839

问:

记录数据时,我想要对包含类的泛型引用。这样,如果将代码移动到其他位置,类名将相应更改。(否则,如果代码移动到 ,它仍将被错误地记录为 )。例如:nameof(Class2)nameof(Class1)

class Class_Name {
   ICommand Command_Name =>
        new RelayCommand(() =>
        {
           // An loggable event occurs

           // Is there a smart and uncomplicated way of doing this generically?
           var provenance = $"{nameof(Class_Name)}.{nameof(Command_Name)}";

           // The event of whatever kind gets logged
      });
   }

   // OR
   void Method_Name() {
      var provenance = $"{nameof(Class_Name)}.{nameof(Method_Name)}";
   }
}

使用泛型 ,其中应引用类本身,会导致编译错误: CS8081: 表达式没有名称。使用会导致同样的问题。nameof(this)thisthis.GetType()

不真正理解为什么关键字在此上下文中不引用包含类。有没有办法笼统地引用当前类?this

C# 这个

评论

1赞 mcjmzn 8/25/2022
而不是使用 use .$"{nameof(this.GetType())}"$"{this.GetType().Name}"
0赞 Denis G. Labrecque 8/25/2022
@mcjmzn CS8082:子表达式不能用于 nameof 的参数中。正如前面在帖子中所表达的那样,首先是无法访问的。关键字似乎在里面无法访问。this.GetType()thisnameof()
0赞 Denis G. Labrecque 8/25/2022
@mcjmzn我忘了指定,这是在 ,而不是在方法中,示例不正确,您的解决方案将起作用。将编辑帖子。ICommand
3赞 mcjmzn 8/25/2022
我的意思是:你不应该将 .用于获取类名。nameofthis.GetType()this.GetType().Name
0赞 Denis G. Labrecque 8/25/2022
@mcjmzn我很抱歉,你是绝对正确的,愚蠢的错误

答:

2赞 mcjmzn 8/25/2022 #1

按设计:

nameof 表达式在编译时计算,在 运行时间。

若要动态访问类型,可以在运行时中使用该方法。只是记得不要将它与 .GetTypenameof

class Class_Name {
   void Method_Name() {
      // An event occurs

      // Is there a smart and uncomplicated way of doing this generically?
      var provenance = $"{this.GetType().Name}.{MethodBase.GetCurrentMethod().Name}";

      // The event of whatever kind gets logged
   }
}

评论

0赞 Jeppe Stig Nielsen 8/25/2022
如果使用 或 只是,则它不等同于,因为该类未标记为 .(这假定在具有基类的类的实例上调用私有方法。$"{this.GetType().Name}"$"{GetType().Name}"nameof(Class_Name)sealedClass_Name
0赞 Denis G. Labrecque 8/25/2022
@JeppeStigNielsen 为什么继承类的实例的类型名称与 不同,实例的类型在哪里?nameof(Class_Name)Class_Name
1赞 Jeppe Stig Nielsen 8/25/2022
@DenisG.Labrecque 我试着做一个.NET小提琴来解释我的意思:在这里试试吧!如果更改为 ,则输出会有所不同。nameof(Class_Name)
0赞 Denis G. Labrecque 8/25/2022
@JeppeStigNielsen感谢您的投入;确实,在调用发生在基方法中的情况下,让子类的名称代表基会造成混淆。
4赞 David L 8/25/2022 #2

如果通过帮助程序方法将注释中的建议与属性相结合,则可以以可重用的方式完成所需的任务。this.GetType().Name)[CallerMemberName]

public class Class_Name
{
    public void Method_Name()
    {
        var provenance = CreateProvenance();
        Console.WriteLine(provenance);
    }

    private string CreateProvenance([CallerMemberName] string methodName = "")
    {
        return $"{this.GetType().Name}.{methodName}";
    }
}

这将输出“Class_Name.Method_Name”。

您甚至可以将其转换为方便的扩展方法,允许您从任何方法调用它。

public class Class_Name
{
    public void Method_Name()
    {
        var provenance = this.CreateProvenance();
        Console.WriteLine(provenance);
    }
}

public static class ProvenanceExtensions
{
    public static string CreateProvenance(this object context, 
        [CallerMemberName] string methodName = "")
    {
        return $"{context.GetType().Name}.{methodName}";
    }
}

正如 Jeppe Stig Nielsen 所指出的,您可能不希望使用继承的运行时类型,而继承运行时类型将返回。如果要改为获取编译时类型,可以使用泛型。context.GetType().Name

public static class ProvenanceExtensions
{
    public static string CreateProvenance<T>(this T context, 
        [CallerMemberName] string methodName = "")
    {
        return $"{typeof(T).Name}.{methodName}";
    }
}

评论

1赞 Jeppe Stig Nielsen 8/25/2022
与我对 mcjmzn 的答案的评论相关,给出的是运行时类型,而不是编译时类型。另一种选择可能是:但是,您想要两种行为中的哪一种取决于您。context.GetType()public static string CreateProvenance<TCompileType>(this TCompileType context, [CallerMemberName] string methodName = "") { return $"{typeof(TCompileType).Name}.{methodName}"; }
1赞 David L 8/25/2022
这是一个很好的标注,在我的回答中非常有意义。我将更新它以记录两者,具体取决于 OP 正在寻找的行为。