1

I read a related question and answer about the nameof operator, but it didn't help me, so I asked it here.

I want to write a wrapper for the C# nameof operator so not only will it will return the name of a class property, but also concatenate it with the class name.

Let's assume a class with single property:

class Foo
{
   public string SomeProperty {get; set;}
}

Now if compiling Console.WriteLine(nameof(Foo.SomeProperty)) with (C# 6 or higher), the result will be:

SomeProperty

So that is it possible to have something like this:

public string PrintFullName(???? object)
{
    //????
}

I put ???? for the input Type, because I don't know what the proper input Type is.

I want the result of the PrintFullName to be:

Foo.SomeProperty

I don't necessarily look for run-time solutions. Any compile-time workaround will also help.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
yekanchi
  • 813
  • 1
  • 12
  • 30
  • 1
    You can't access `Foo.SomeProperty` since SomeProperty is an instance member of `Foo`. You can olny write `instanceOfFoo.SomeProperty`. You only may use reflexion on the class type to get members definitions. –  Sep 25 '19 at 15:28
  • 1
    @OlivierRogier `Console.WriteLine(nameof(Foo.SomeProperty))` is now a valid C# expression for C# 6 – yekanchi Sep 25 '19 at 15:30
  • It's still not clear - assuming that you got this to work, *why* would `PrintFullName` return "Foo.SomeProperty"? What is the connection between the two? – Scott Hannen Sep 25 '19 at 15:30
  • Maybe you meant something like `Console.WriteLine(typeof(Foo).Name + "." + nameof(Foo.SomeProperty));` ? – Matthew Watson Sep 25 '19 at 15:31
  • @MatthewWatson it prints the result but is it possible to wrap it inside something that inputs the property alone? – yekanchi Sep 25 '19 at 15:32
  • @yekanchi Cool! Very usefull. Thanks. This works: `Console.WriteLine(nameof(Foo) + "." + nameof(String.SomeProperty));` –  Sep 25 '19 at 15:38

2 Answers2

2

Sure this is possible, using expression trees.

A full explanation on this site (all credits to Dave Glick).

It comes down to this:

public void UseNames(string className, string memberName)
{
    // Your code to use the class & membername go here
}

public void UseNames<T>(Expression<Func<T, object>> expression)
{
    MemberExpression member = expression.Body as MemberExpression;
    if (member == null)
    {
        // The property access might be getting converted to object to match the func
        // If so, get the operand and see if that's a member expression
        member = (expression.Body as UnaryExpression)?.Operand as MemberExpression;
    }
    if (member == null)
    {
        throw new ArgumentException("Action must be a member expression.");
    }

    // Pass the names on to the string-based UseNames method
    UseNames(typeof(T).Name, member.Member.Name);
}

public void UseNames<T>(Expression<Func<T, string>> expression)
{
    ConstantExpression constant = expression.Body as ConstantExpression;
    if (constant == null)
    {
        throw new ArgumentException("Expression must be a constant expression.");
    }
    UseNames(typeof(T).Name, constant.Value.ToString());
}

Use it like this:

UseNames<Foo>(x => nameof(x.Bar));
UseNames<Foo>(x => nameof(x.Baz));
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
GvS
  • 52,015
  • 16
  • 101
  • 139
1

A simple (and maybe faster) solution, without expression trees (which use reflection):

public string PrintFullName<T>(String memberName)
{
    return $"{typeof(T).Name}.{memberName}";
}

Usage:

PrintFullName<SomeType>(nameof(SomeType.SomeProperty));
// Compiled to: PrintFullName<SomeType>("SomeProperty");

nameof() is a compile-time construct, so no need to build a slightly advanced solution that performs evaluation at runtime more than required.

Florian S.
  • 206
  • 1
  • 5