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.

6
  • 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. Commented Sep 25, 2019 at 15:28
  • 1
    @OlivierRogier Console.WriteLine(nameof(Foo.SomeProperty)) is now a valid C# expression for C# 6 Commented Sep 25, 2019 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? Commented Sep 25, 2019 at 15:30
  • Maybe you meant something like Console.WriteLine(typeof(Foo).Name + "." + nameof(Foo.SomeProperty)); ? Commented Sep 25, 2019 at 15:31
  • @MatthewWatson it prints the result but is it possible to wrap it inside something that inputs the property alone? Commented Sep 25, 2019 at 15:32

2 Answers 2

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));
Sign up to request clarification or add additional context in comments.

1 Comment

Why the nameof? Your code seems to work with UseNames<Foo>(x => x.Bar).
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.