1

What I have:

public class ClassA: Class C
{
    public string Prop1 {get;set;}
    public ClassB Prop2 {get; set;}
}

public class ClassB: Class C
{
    public int Prop3 {get; set;}
}

I want a method like nameof() which will behave something like this:

string myString = GetPropertyName(ClassA.Prop2.Prop3);

myString:

"ClassB\Prop2\Prop3"

public string GetPropertyName(<no idea what the parameter type should be>)
{
    I cant still fiqure out how to get the full name and how to put / in between, but what to put 
    as parameter so that I can put the properties as parameters like we do in name of?
}
SunainaDG
  • 109
  • 1
  • 14
  • 1
    seems like you don´t wnat the property name, but the entire path to it. Maybe you can pass an `Expression`. – MakePeaceGreatAgain Jul 03 '20 at 11:28
  • I don't think something like this is going to be useful. If you need it in a real application, I doubt you're moving in the wrong path. But that's a personal opinion. – Youssef13 Jul 03 '20 at 11:31
  • aye, this certainly *can* be done via the `Expression<>` API, but... that's really pretty expensive at runtime; how often does this thing evaluate? – Marc Gravell Jul 03 '20 at 11:44

2 Answers2

1

If performance is not taken into consideration you can try to look into expression trees. Starting point would be something like this:

public static string GetPropertyPath<T, TProp>(Expression<Func<T, TProp>> expr)
{
    var pathParts = new List<string>();
    var body = expr.Body;
    var cont = true;
    while(cont)
    {
        switch(body)
        {
            case MemberExpression me:
                body = me.Expression;
                pathParts.Add(me.Member.Name);
                break;
            case ParameterExpression pe: 
                cont = false;
                pathParts.Add(pe.Type.Name);
                break;
            default: body.Dump(); throw new InvalidOperationException();
        }
    }
    
    pathParts.Reverse();
    return string.Join("\\", pathParts);
} 

Console.WriteLine(GetPropertyName((ClassA x) => x.Prop2.Prop3)); // prints ClassA\Prop2\Prop3

This can be improved but there are many downsides to this solution - some of compile time safety is lost (see the exceptions), performance (though you can try cache some results, but it is separate hard topic and it still will not be anywhere near the nameof). Another option would be to look into IL weaving(for example with Fody), but not sure where you can go with it.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
0

You can use MemberExpression. Based on this answer with small adjustments for you case could be implemented in form of extension method

public static class PropertyExtensions
{
    public static string GetPropertyFullPath<T, R>(this T obj, Expression<Func<T, R>> expression)
    {
        var buffer = new List<string>();
        var memberExpresiion = expression.Body as MemberExpression;
        while (memberExpresiion != null)
        {
            buffer.Add(memberExpresiion.Member.Name);
            if (memberExpresiion.Expression as MemberExpression == null)
            {
                buffer.Add(memberExpresiion.Member.DeclaringType.Name);
                break;
            }
            memberExpresiion = memberExpresiion.Expression as MemberExpression;
        }
        buffer.Reverse();
        return string.Join('/', buffer);
    }
}

Usage:

        var t = new D();
        Console.WriteLine(t.GetPropertyFullPath(_ => _.Top.Deep.Deeper.VeryDeep));
n.prokhorov
  • 930
  • 7
  • 13