1

From this SO answer I'm trying to build a text replace function.

The problem is that it can't do multi level. Or at least I don't know how.

If I have this query:

var foo = await _dbContext.Foos.Include(x => x.Bar).AsNoTracking().FirstOrDefaultAsync(x => x.Id == someId);

I can do:

var fooName = GetPropertyValue(foo, "Name");

But I can't do:

var barName = GetPropertyValue(foo, "Bar.Name");

Is that possible?

public class Foo
{
    public string Name {get;set;}
    public Guid BarId {get;set;}
    public Bar Bar {get;set;}
}

public class Bar
{
    public string Name {get;set;}
}
Svyatoslav Danyliv
  • 21,911
  • 3
  • 16
  • 32
Mads
  • 385
  • 1
  • 5
  • 18
  • 1
    Looks like answer is not suitable for your needs. Also do you really need to retrieve value from already loaded WHOLE objects, or you just need one field from database? – Svyatoslav Danyliv Oct 24 '22 at 11:07
  • My goal is to make a dynamic replace method like `someString.Replace("{foo.Bar.Name}", GetPropertyValue(foo, "Bar.Name")` so I have to be able to retrieve any value from the query. Maybe I have to convert the query to JSON to make that possible. – Mads Oct 24 '22 at 11:31

2 Answers2

1

You need a recursive version of the aforementioned method. You may try something like below:

        public static string? GetPropertyValue(object source, string propertyName)
        {
            try
            {
                return GetInnerProp(source, propertyName) as string;
            }
            catch { return null; }
        }

        private static object GetInnerProp(object source, string propertyName)
        {
            if (propertyName.Contains('.'))
            {
                var propertyNames = propertyName.Split(".");
                var firstProp = propertyNames.First();
                var newSource = source.GetType().GetProperty(firstProp).GetValue(source, null);
                var rest = string.Join(".", propertyNames.Skip(1));

                return GetInnerProp(newSource, rest);
            }

            return source.GetType().GetProperty(propertyName).GetValue(source, null);
         
        }

It basically split the property name and recursively walks from left to right to access the right property. You also will need an inner method that returns an object as the nested object will have a type other than string.

Fiddle

Eldar
  • 9,781
  • 2
  • 10
  • 35
  • Looks like we're on the right track. I can now get a value from `foo.Bar.Name` but not `foo.Name`? – Mads Oct 24 '22 at 11:44
  • The reason was that the method only returned a value, if the property was a string. When I changed the GetPropertyValue method to return an object and in the output converted that object to a string, it worked. Thanks! – Mads Oct 24 '22 at 13:34
0

You simply need to the function twice, once to get the Bar object and once again to get the Name property of Bar:

var bar = GetPropertyValue(foo, "Bar");
var barName = GetPropertyValue(bar , "Name");

This should give the desired result.

Poul Bak
  • 10,450
  • 5
  • 32
  • 57
  • You're right, I could do that, but that wouldn't work in my example, as I trying to make a dynamic replace method like `someString.Replace("{foo.Bar.Name}", GetPropertyValue(foo, "Bar.Name")` – Mads Oct 24 '22 at 11:32