Coder 2
Coder 2

Reputation: 4881

How to get a property value based on the name

is there a way to get the value of a property of a object based on its name?

For example if I have:

public class Car : Vehicle
{
   public string Make { get; set; }
}

and

var car = new Car { Make="Ford" };

I want to write a method where I can pass in the property name and it would return the property value. ie:

public string GetPropertyValue(string propertyName)
{
   return the value of the property;
}

Upvotes: 191

Views: 251040

Answers (10)

HackSlash
HackSlash

Reputation: 5805

Expanding upon the answer given by @zwcloud, we can use any property type if you are using a version of .NET that supports the dynamic type.

Then if you need to dynamically load settings into a property you only have the string name of, you need a separate setter dictionary.

Now we arrive at a solution where we can get or set any property by name. It does take a lot of ceremony to get here but it ends up being much better than reflection.

To make an extension out of this we would need to get into code weaving, where this code could be generated for you at compile time. Tune in next time for another exciting episode of "ain't nobody got time for that".

public class Car
{
    public string MakeA { get; set; }
    public int MakeB { get; set; }
    public decimal MakeC { get; set; }

    private readonly Dictionary<string, Func<dynamic>> _propertyGetterMap;
    
    private readonly Dictionary<string, Action<dynamic>> _propertySetterMap;

    public Car()
    {
        _propertyGetterMap= new Dictionary<string, Func<dynamic>>(3)
        {
            { nameof(MakeA), () => MakeA },
            { nameof(MakeB), () => MakeB },
            { nameof(MakeC), () => MakeC }
        };

        _propertySetterMap= new Dictionary<string, Func<dynamic>>(3)
        {
            { nameof(MakeA), (value) => MakeA = value.ToString() },
            { nameof(MakeB), (value) => MakeB = (int)Convert.ChangeType(value, typeof(int)) },
            { nameof(MakeC), (value) => MakeC = (decimal)Convert.ChangeType(value, typeof(decimal)) }
        };
    }

    public string GetPropertyValue(string propertyName)
    {
        if (_stringPropertyMap.TryGetValue(propertyName, out var getter))
        {
            return getter();
        }

        throw new InvalidOperationException($"{nameof(Car)} doesn't have a property of name {propertyName}");
    }

    public string SetPropertyValue(string propertyName, dynamic value)
    {
        if (_stringPropertyMap.TryGetValue(propertyName, out var setter))
        {
            setter(value);
        }

        throw new InvalidOperationException($"{nameof(Car)} doesn't have a property of name {propertyName}");
    }
}

Upvotes: 0

zwcloud
zwcloud

Reputation: 4889

Here is a faster way by creating your own customized RTTI.

public class Car
{
    public string MakeA { get; set; }
    public string MakeB { get; set; }
    public string MakeC { get; set; }

    private readonly Dictionary<string, Func<string>> _stringPropertyMap;
    //For properties of other types, add different typed Dictionary like _stringPropertyMap

    public Car()
    {
        _stringPropertyMap = new Dictionary<string, Func<string>>(3)
        {
            { nameof(MakeA), () => MakeA },
            { nameof(MakeB), () => MakeB },
            { nameof(MakeC), () => MakeC }
        };
    }

    public string GetPropertyValue(string propertyName)
    {
        if (_stringPropertyMap.TryGetValue(propertyName, out var getter))
        {
            return getter();
        }

        throw new InvalidOperationException($"{nameof(Car)} doesn't have a property of name {propertyName}");
    }
}

Upvotes: 1

Loesil
Loesil

Reputation: 11

2 Very short options, 1 with a default value if it fails:

public object GetPropertyValue_WithDefault(
    object _t,
    string _prop,
    object _default = null
)
{
    PropertyInfo pi = _t.GetType().GetProperty(_prop);
    return (pi == null
        ? _default
        : pi.GetValue(_t, null)
    );
}

public object GetPropertyValue(object _t, string _prop)
{
    //because of "?." will return null if property not found
    return _t.GetType().GetProperty(_prop)?.GetValue(_t, null); 
}

Upvotes: 1

Paul McCarthy
Paul McCarthy

Reputation: 886

To avoid reflection you could set up a Dictionary with your propery names as keys and functions in the dictionary value part that return the corresponding values from the properties that you request.

Upvotes: 3

Cameron Forward
Cameron Forward

Reputation: 712

Expanding on Adam Rackis's answer - we can make the extension method generic simply like this:

public static TResult GetPropertyValue<TResult>(this object t, string propertyName)
{
    object val = t.GetType().GetProperties().Single(pi => pi.Name == propertyName).GetValue(t, null);
    return (TResult)val;
}

You can throw some error handling around that too if you like.

Upvotes: 11

Ali
Ali

Reputation: 3469

In addition other guys answer, its Easy to get property value of any object by use Extension method like:

public static class Helper
    {
        public static object GetPropertyValue(this object T, string PropName)
        {
            return T.GetType().GetProperty(PropName) == null ? null : T.GetType().GetProperty(PropName).GetValue(T, null);
        }

    }

Usage is:

Car foo = new Car();
var balbal = foo.GetPropertyValue("Make");

Upvotes: 8

Sith2021
Sith2021

Reputation: 3716

Simple sample (without write reflection hard code in the client)

class Customer
{
    public string CustomerName { get; set; }
    public string Address { get; set; }
    // approach here
    public string GetPropertyValue(string propertyName)
    {
        try
        {
            return this.GetType().GetProperty(propertyName).GetValue(this, null) as string;
        }
        catch { return null; }
    }
}
//use sample
static void Main(string[] args)
    {
        var customer = new Customer { CustomerName = "Harvey Triana", Address = "Something..." };
        Console.WriteLine(customer.GetPropertyValue("CustomerName"));
    }

Upvotes: 8

Adam Rackis
Adam Rackis

Reputation: 83358

You'd have to use reflection

public object GetPropertyValue(object car, string propertyName)
{
   return car.GetType().GetProperties()
      .Single(pi => pi.Name == propertyName)
      .GetValue(car, null);
}

If you want to be really fancy, you could make it an extension method:

public static object GetPropertyValue(this object car, string propertyName)
{
   return car.GetType().GetProperties()
      .Single(pi => pi.Name == propertyName)
      .GetValue(car, null);
}

And then:

string makeValue = (string)car.GetPropertyValue("Make");

Upvotes: 58

Chuck Savage
Chuck Savage

Reputation: 11945

You want Reflection

Type t = typeof(Car);
PropertyInfo prop = t.GetProperty("Make");
if(null != prop)
return prop.GetValue(this, null);

Upvotes: 44

Matt Greer
Matt Greer

Reputation: 62027

return car.GetType().GetProperty(propertyName).GetValue(car, null);

Upvotes: 381

Related Questions