Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Type name of a CallerMember

Tags:

c#

I got this class

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     } } 

And This Attribue Class

// 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      } } 

Then I have this

public class CustClass : fooBase {      [CustomAttribute()]      public string method1()      {          if (fooMethod())          {              ....          }      } } 

I need the Type name of the CallerMember, there is something like [CallerMemberName] to get the Type of class owner of the Caller ?

like image 634
Juan Pablo Gomez Avatar asked Jul 27 '13 03:07

Juan Pablo Gomez


People also ask

How can I get the class name that calls my method?

You can use StackFrame of System. Diagnostics and MethodBase of System. Reflection . StackFrame(Int32, Boolean) initializes a new instance of the StackFrame class that corresponds to a frame above the current stack frame, optionally capturing source information.

What is CallerMemberName in C#?

[CallerMemberName] applies the caller's member name. [CallerFilePath] applies the path to the caller's source code file. [CallerLineNumber] applies the line number in the caller's source code file.


2 Answers

It isn't foolproof, but the convention with .NET is to have one type per file and to name the file the same as the type. Our tooling also tends to enforces this convention i.e. Resharper & Visual Studio.

Therefore it should be reasonable to infer the type name from the file path.

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);   } } 
like image 119
Paul Avatar answered Oct 03 '22 06:10

Paul


Caller member

Granted, getting the caller member name is not "natural" in the object model. That's why the C# engineers introduced CallerMemberName in the compiler.

The real enemy is duplication, and stack-based workarounds are inefficient.

[CallerMemberName] allows to get the information without duplication and without ill-effect.

Caller type

But getting the caller member type is natural and easy to get without duplication.

How to do it

Add a "caller" parameter to fooMethod, no special attribute needed.

    public bool fooMethod(object caller, [CallerMemberName]string membername = "")     {         Type callerType = caller.GetType();         //This returns a value depending of type and method         return true;     } 

And call it like this:

fooMethod(this); 

This answer the question

You stated

// Here I want to get CustClass, not fooBase

and that's exactly what you'll get.


Other situations where it would not work, with solutions.

While this exactly answers your requirements, there are other, different, cases where it wouldn't work.

  • Case 1: When caller is a static methods (there is no "this").
  • Case 2: When one wants the type of the caller method itself, and not the type of the caller itself (which may be a subclass of the first).

In those cases, a [CallerMemberType] might make sense, but there are simpler solutions. Notice that the static caller case is simpler: there is no object so no discrepancy between it and the type of the calling method. No fooBase, only CustClass.

Case 1: When caller is a static methods (there is no "this")

If at least one caller is a static method, then don't do the GetType() inside the method but on call site, so don't pass "this" to the method but the type:

public bool fooMethodForStaticCaller(Type callerType, [CallerMemberName]string membername = "") 

Static caller will do:

public class MyClassWithAStaticMethod  // can be CustClass, too {     public static string method1static()     {         fooMethodForStaticCaller(typeof(MyClassWithAStaticMethod));     } } 

To keep compatibility with object callers, either keep the other fooMethod that takes the this pointer, or you can remove it and object callers will do:

fooMethod(this.GetType()); 

You can notice that the typeof(MyClassWithAStaticMethod) above repeats the class name and it's true. It would be nicer to not repeat the class name, but it's not such a big deal because this repeats only once, as a typed item (not a string) and inside the same class. It's not as serious a problem as the original problem that the [CallerMemberName] solves, which was a problem of repeating the caller name in all call sites.

Case 2: When one wants the type of the caller method, not the type of the caller

For example, in class fooBase you want to call anotherFooMethod from object context but want the type being passed to always be fooBase, not the actual type of the object (e.g. CustClass).

In this case there is a this pointer but you don't want to use it. So, just use actually the same solution:

public class fooBase {      [CustomAttribute()]      public string method1()      {          if (anotherFooMethod(typeof(fooBase)))          {              ....          }      } } 

Just like in case 1, there is one repetition, not one per call site, unless you have an pre-existing problem of rampant code duplication, in which case the problem being addressed here is not the one you should worry about.

Conclusion

[CallerMemberType] might still make sense to avoid duplication at all, but:

  • anything added to the compiler is a complexity burden with maintenance cost
  • given the existing solutions I'm not surprised there are items with higher priority in the C# development team list.
like image 42
Stéphane Gourichon Avatar answered Oct 03 '22 05:10

Stéphane Gourichon