Reputation: 4881
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
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
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
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
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
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
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
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
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
Reputation: 11945
You want Reflection
Type t = typeof(Car);
PropertyInfo prop = t.GetProperty("Make");
if(null != prop)
return prop.GetValue(this, null);
Upvotes: 44
Reputation: 62027
return car.GetType().GetProperty(propertyName).GetValue(car, null);
Upvotes: 381