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;
}
return car.GetType().GetProperty(propertyName).GetValue(car, null);
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");
You want Reflection
Type t = typeof(Car);
PropertyInfo prop = t.GetProperty("Make");
if(null != prop)
return prop.GetValue(this, null);
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.
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");
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"));
}
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.
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);
}
Related
C# has the usefull Null Conditional Operator. Well explained in this answer too.
I was wondering if it is possible to do a similar check like this when my object is a dynamic/expando object. Let me show you some code:
Given this class hierarchy
public class ClsLevel1
{
public ClsLevel2 ClsLevel2 { get; set; }
public ClsLevel1()
{
this.ClsLevel2 = new ClsLevel2(); // You can comment this line to test
}
}
public class ClsLevel2
{
public ClsLevel3 ClsLevel3 { get; set; }
public ClsLevel2()
{
this.ClsLevel3 = new ClsLevel3();
}
}
public class ClsLevel3
{
// No child
public ClsLevel3()
{
}
}
If i perform this kind of chained null check, it works
ClsLevel1 levelRoot = new ClsLevel1();
if (levelRoot?.ClsLevel2?.ClsLevel3 != null)
{
// will enter here if you DO NOT comment the content of the ClsLevel1 constructor
}
else
{
// will enter here if you COMMENT the content of the ClsLevel1
}
Now, i will try to reproduce this behaviour with dynamics (ExpandoObjects)
dynamic dinRoot = new ExpandoObject();
dynamic DinLevel1 = new ExpandoObject();
dynamic DinLevel2 = new ExpandoObject();
dynamic DinLevel3 = new ExpandoObject();
dinRoot.DinLevel1 = DinLevel1;
dinRoot.DinLevel1.DinLevel2 = DinLevel2;
//dinRoot.DinLevel1.DinLevel2.DinLevel3 = DinLevel3; // You can comment this line to test
if (dinRoot?.DinLevel1?.DinLevel2?.DinLevel3 != null)
{
// Obviously it will raise an exception because the DinLevel3 does not exists, it is commented right now.
}
Is there a way to simulate this behaviour with dynamics? I mean, check for a null in a long chain of members?
If you want to support this in a more natural way you can inherit from DynamicObject and provide a custom implementation:
class MyExpando : DynamicObject
{
private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var name = binder.Name.ToLower();
result = _dictionary.ContainsKey(name) ? _dictionary[name] : null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dictionary[binder.Name.ToLower()] = value;
return true;
}
}
Testing:
private static void Main(string[] args)
{
dynamic foo = new MyExpando();
if (foo.Boo?.Lol ?? true)
{
Console.WriteLine("It works!");
}
Console.ReadLine();
}
The output will be "It works!". Since Boo does not exist we get a null reference so that the Null Conditional Operator can work.
What we do here is to return a null reference to the output parameter of TryGetMember every time a property is not found and we always return true.
EDIT: fixed, as ExpandoObjects and extension methods do not work well together. Slightly less nice, but hopefully still usable.
Helper method(s):
public static class DynamicExtensions
{
public static Object TryGetProperty(ExpandoObject obj, String name)
{
return name.Split('.')
.Aggregate((Object)obj, (o, s) => o != null
? TryGetPropertyInternal(o, s)
: null);
}
private static Object TryGetPropertyInternal(Object obj, String name)
{
var dict = obj as IDictionary<String, Object>;
return (dict?.ContainsKey(name) ?? false) ? dict[name] : null;
}
}
Usage:
if (DynamicExtensions.TryGetProperty(dinRoot, "DinLevel1.DinLevel2.DinLevel3") != null)
i wrote some code to get all classes implementing an Interface.
private static List<ClassNameController> getClassesByInheritInterface(Type interfaceName)
{
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => interfaceName.IsAssignableFrom(p) && !p.IsInterface);
List<ClassNameController> myControllerList = new List<ClassNameController>();
foreach (System.Type type in types)
{
// Get a PropertyInfo of specific property type(T).GetProperty(....)
PropertyInfo propertyInfo;
propertyInfo = type
.GetProperty("className", BindingFlags.Public | BindingFlags.Static);
// Use the PropertyInfo to retrieve the value from the type by not passing in an instance
object value = propertyInfo.GetValue(null, null);
// Cast the value to the desired type
string typedValue = (string)value;
myControllerList.Add(new ClassNameController(typedValue, type));
}
return myControllerList;
}
}
All of these classes got a public static string className Property. The Value of this Property I use to create an ClassNameController Instance
class ClassNameController
{
public string Name { get; set; }
public System.Type ObjectType { get; set; }
public ClassNameController(string name, Type objectType)
{
this.Name = name;
this.ObjectType = objectType;
}
public override string ToString()
{
return Name;
}
}
But when i start my Program it crashes at
object value = propertyInfo.GetValue(null, null);
with the error message
System.NullReferenceException.
Question: So why cant he find the Property Classname?
Edit:
All Classes are implementing these interfaces are WPF UserControls.
For example IModuleview:
internal interface IModuleView
{
void updateShownInformation();
void setLanguageSpecificStrings();
}
And here an example of a Module:
public partial class DateBox : UserControl, IModuleView
{
public static string className = "Datebox";
public DateBox()
{
InitializeComponent();
}
public void setLanguageSpecificStrings()
{
this.ToolTip = DateTime.Now.ToString("dddd, dd.MM.yy");
}
public void updateShownInformation()
{
tbDate.Text = DateTime.Now.ToString("ddd-dd");
}
}
So why cant he find the Property Classname?
Looking at the declaration in your posted class DateBox:
public static string className = "Datebox";
It has the signature of a field
Hence you should use the GetField method:
object value = type.GetField("className",
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Static).GetValue(null);
Explanation: What is the difference between a Field and a Property in C#?
Is it possible to map a database column to a constant value without the need for a property in the entity class? This basically is a workaround for a missing default value on that column in the database in combination with a NOT NULL constrained. The database is external and can't be changed but I don't need all of the columns in that table and thus don't want to have corresponding properties in my entity class.
I am asking basically the same as described in this Hibernate JIRA issue.
Based on Firos answer I solved the problem. However, I didn't quite like the syntax to be used and the fact that I would have to create a new class for the default values for each entity.
The syntax I got now looks like this:
mapping.ConstantValue(0).Column(#"client_id");
// or
mapping.ConstantValue(0, #"client_id");
I created the following extension methods for it:
public static PropertyPart
ConstantValue<TType, TValue>(this ClasslikeMapBase<TType> map, TValue value)
{
var getter =
new ConstantValueGetter<TValue>(CreateUniqueMemberName(), value);
ConstantValueAccessor.RegisterGetter(typeof(TType), getter);
var propertyInfo =
new GetterSetterPropertyInfo(typeof(TType), typeof(TValue),
getter.PropertyName, getter.Method, null);
var parameter = Expression.Parameter(typeof(TType), "x");
Expression body = Expression.Property(parameter, propertyInfo);
body = Expression.Convert(body, , typeof(object));
var lambda = Expression.Lambda<Func<TType, object>>(body, parameter);
return map.Map(lambda).Access.Using<ConstantValueAccessor>();
}
public static PropertyPart
ConstantValue<TType, TValue>(this ClasslikeMapBase<TType> map,
TValue value, string column)
{
return map.ConstantValue(value).Column(column);
}
The important differences are:
The first of those extension methods returns a PropertyPart and has to be used in conjunction with the Column method to specify which column the constant value should be mapped to. Because of this, the column name is not known when the extension method is executed and we need to create one ourselves. This is done by CreateUniqueMemberName:
private static string CreateUniqueMemberName()
{
return "Dummy" + Guid.NewGuid().ToString("N");
}
Because you can only specify a type as access strategy and not an instance, I couldn't create an IPropertyAccessor implementation allowed me to simply pass an IGetter instance in the constructor. That's what ConstantValueAccessor.RegisterGetter(typeof(TType), getter); solves. ConstantValueAccessor has a static collection of getters:
internal class ConstantValueAccessor : IPropertyAccessor
{
private static readonly
ConcurrentDictionary<Type, SynchronizedCollection<IGetter>> _getters =
new ConcurrentDictionary<Type, SynchronizedCollection<IGetter>>();
public static void RegisterGetter(Type type, IGetter getter)
{
var getters =
_getters.GetOrAdd(type,
t => new SynchronizedCollection<IGetter>());
getters.Add(getter);
}
public IGetter GetGetter(Type theClass, string propertyName)
{
SynchronizedCollection<IGetter> getters;
if (!_getters.TryGetValue(theClass, out getters))
return null;
return getters.SingleOrDefault(x => x.PropertyName == propertyName);
}
// ...
}
The implementation of ConstantValueGetter<T> is the same as the one from the provided link.
Because it wasn't that much fun to implement GetterSetterPropertyInfo, here it is. One important difference is, that this implementation doesn't have any dependencies on (Fluent) NHibernate.
My implementation takes the same idea as hival but goes a lot further. the basis is an implementation of IPropertyAccessor
/// <summary>
/// Defaultvalues für nicht (mehr) benötigte Spalten siehe
/// http://elegantcode.com/2009/07/13/using-nhibernate-for-legacy-databases/
/// </summary>
public abstract class DefaultValuesBase : IPropertyAccessor
{
public abstract IEnumerable<IGetter> DefaultValueGetters { get; }
public bool CanAccessThroughReflectionOptimizer
{
get { return false; }
}
public IGetter GetGetter(Type theClass, string propertyName)
{
return DefaultValueGetters.SingleOrDefault(getter => getter.PropertyName == propertyName);
}
public ISetter GetSetter(Type theClass, string propertyName)
{
return new NoopSetter();
}
}
// taken from the link
[Serializable]
public class DefaultValueGetter<T> : IGetter {...}
// ---- and the most tricky part ----
public static void DefaultValues<T>(this ClasslikeMapBase<T> map, DefaultValuesBase defaults)
{
DefaultValuesInternal<T>(map.Map, defaults);
}
public static void DefaultValues<T>(this CompositeElementPart<T> map, DefaultValuesBase defaults)
{
DefaultValuesInternal<T>(map.Map, defaults);
}
private static void DefaultValuesInternal<T>(
Func<Expression<Func<T, object>>, PropertyPart> mapFunction, DefaultValuesBase defaults)
{
var noopSetter = new NoopSetter();
var defaultsType = defaults.GetType();
foreach (var defaultgetter in defaults.DefaultValueGetters)
{
var parameter = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Property(parameter,
new GetterSetterPropertyInfo(typeof(T), defaultgetter, noopSetter));
body = Expression.Convert(body, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, parameter);
mapFunction(lambda).Column(defaultgetter.PropertyName).Access.Using(defaultsType);
}
}
// GetterSetterPropertyInfo inherits PropertyInfo with important part
public override string Name
{
get { return m_getter.PropertyName; } // propertyName is the column in db
}
// and finally in SomeEntityMap
this.DefaultValues(new SomeEntityDefaults());
public class SomeEntityDefaults : DefaultValuesBase
{
public override IEnumerable<IGetter> DefaultValueGetters
{
get
{
return new [] {
new DefaultValueGetter<int>("someColumn", 1),
new DefaultValueGetter<string>("somestrColumn", "empty"),
};
}
}
}
If you don't want to introduce property in your entity class the only solution I see is to create custom property accessor which will always return constant value. Here is possible implementation:
public class ConstantAccessor : IPropertyAccessor
{
#region IPropertyAccessor Members
public IGetter GetGetter(Type theClass, string propertyName)
{
return new ConstantGetter();
}
public ISetter GetSetter(Type theClass, string propertyName)
{
return new NoopSetter();
}
public bool CanAccessThroughReflectionOptimizer
{
get { return false; }
}
#endregion
[Serializable]
private class ConstantGetter : IGetter
{
#region IGetter Members
public object Get(object target)
{
return 0; // Always return constant value
}
public Type ReturnType
{
get { return typeof(object); }
}
public string PropertyName
{
get { return null; }
}
public MethodInfo Method
{
get { return null; }
}
public object GetForInsert(object owner, IDictionary mergeMap,
ISessionImplementor session)
{
return null;
}
#endregion
}
[Serializable]
private class NoopSetter : ISetter
{
#region ISetter Members
public void Set(object target, object value)
{
}
public string PropertyName
{
get { return null; }
}
public MethodInfo Method
{
get { return null; }
}
#endregion
}
}
Here how to use it:
<property name="Value"
access="ConsoleApplication2.ConstantAccessor, ConsoleApplication2"
column="a_value" type="int" />
Property "Value" doesn't need to exist in your entity. It is here because attribute "name" is required.
I need to call SetSettings() and using the 3 elements in splitSettings, set EncodeAudio to False.
How would I go about doing that? Convert the property of a object to who's name I have in a string.
I realize I could do with with a switch statement of all my settings but there has to be a more dynamic way to go about doing this.
namespace SettingsLib
{
public class Settings
{
public Boolean EncodeAudio { get; set; }
}
}
namespace Service
{
void SetSettings()
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
// Need to set EncodeAudio to False in SettingsLib.Settings
}
}
Yes I have a instance of Settings
Say:
Settings settingManager = new Settings();
I am trying to do is dynamically set EncodeAudo to False by using elements of splitSettings
settingManager.EncodeAudio = False;
Thanks to the help of TBohnen.jnr
I came to this answer:
public void setProperty(object containingObject, string propertyName, object newValue)
{
foreach (PropertyInfo p in containingObject.GetType().GetProperties())
{
if (p.Name == propertyName)
{
p.SetValue(containingObject, Convert.ChangeType(newValue, p.PropertyType), null);
}
}
}
EDIT Tested it with int, bool, double and string and it worked, also added a check to make sure that the property exists and throws an exception of it doesn't (Might want to change Exception type)
EDIT 2: Temporary solution, will add more typenames to the convert method or alternatively if somebody can suggest a more dynamic way of casting it (If not then I assume you will have to know all of the types that will be used)?
EDIT3 Stole the convert method from another answer in question (Chris Taylor ), thanks :-)
public void setProperty(object containingObject, string propertyName, object newValue)
{
if (containingObject.GetType().GetProperties().Count(c => c.Name == propertyName) > 0)
{
var type = containingObject.GetType().GetProperties().First(c => c.Name == propertyName).PropertyType;
object val = Convert(type,(string)newValue);
containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new object[] { val });
}
else
{
throw new KeyNotFoundException("The property: " + propertyName + " was not found in: " + containingObject.GetType().Name);
}
}
public object convert(System.Type type, string value)
{
return Convert.ChangeType(value, type);
}
Taken from http://www.haslo.ch/blog/setproperty-and-getproperty-with-c-reflection/
Was interested to see if this works, create a quick test:
class testSettings
{
public bool SetBool { get; set; }
public void setProperty(object containingObject, string propertyName, object newValue)
{
if (containingObject.GetType().GetProperties().Count(c => c.Name == propertyName) > 0)
{
containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new object[] { newValue });
}
else
{
throw new KeyNotFoundException("The property: " + propertyName + " was not found in: " + containingObject.GetType().Name);
}
}
}
static void Main(string[] args)
{
testSettings ts = new testSettings();
ts.SetBool = false;
ts.setProperty(ts, "SetBool", true);
Console.WriteLine(ts.SetBool.ToString());
Console.Read();
}
The output is true, not entirely sure if it will convert all types correctly though.
As others have mentioned, you should consider making your SettingsLib class static. And you might also need to handle the conversion of values from strings to the target types. Here is a simple example how this would work.
namespace Service
{
class Program
{
static void Main(string[] args)
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
SetProperty(splitSettings[0], splitSettings[1], splitSettings[2]);
}
static void SetProperty(string typeName, string propertyName, object value)
{
var type = Type.GetType(typeName);
if (type == null)
{
throw new ArgumentException("Unable to get type", "typeName");
}
var pi = type.GetProperty(propertyName);
if (pi == null)
{
throw new ArgumentException("Unable to find property on type", "propertyName");
}
object propertyValue = value;
if (propertyValue != null)
{
// You might need more elaborate testing here to ensure that you can handle
// all the various types, you might need to special case some types here
// but this will work for the basics.
if (pi.PropertyType != propertyValue.GetType())
{
propertyValue = Convert.ChangeType(propertyValue, pi.PropertyType);
}
}
pi.SetValue(null, propertyValue, null);
}
}
}
namespace SettingsLib
{
public static class Settings
{
public static bool EncodeAudio { get; set; }
}
}
Maybe you should mark your settable properties as static and then try to set the values using Reflection:
namespace SettingsLib
{
public static class Settings
{
public static bool EncodeAudio { get; set; }
}
}
namespace Service
{
void SetSettings()
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
dynamic property = Type.GetType(splitSettings[0]).GetProperty(splitSettings[1]);
property = splitSettings[2];
}
}
At times when we access Session["key"].ToString() it gives exception when session is expired & in coding we try to access session variable. So I'm trying to create extension method on object class so that I could write it as Session["key"].getString() in coding so that every time I don't have to do Convert.ToString(session["key"])
Any other solutions are also appreciable.
Just use the null-coalescing operator:
string value = (session["key"] ?? String.Empty).ToString();
Update
If you must have a method to do this (extension or otherwise), I would do something like:
public static string GetValue(this HttpSessionState session, string key)
{
// TODO: Insert appropriate error checking here.
return (session[key] ?? String.Empty).ToString();
}
I might even go so far as to make it generic for other possible types with a GetValue call that takes a selector and then use lambdas:
public static T GetValue<T>(this HttpSessionState session, string key, Func<object, T> valueSelector)
{
return valueSelector(session[key]);
}
public static string GetStringValue(this HttpSessionState session, string key)
{
return session.GetValue(key, x => (x ?? String.Empty).ToString());
}
You would then use as follows:
string value = session.GetStringValue("key");
public static class ObjectExtensions
{
public static string GetString(this object o)
{
if (o == null)
{
return string.Empty;
}
return Convert.ToString(o);
}
}
and then:
string value = Session["key"].GetString();
or check this one:
public static class SessionExtensions
{
public static string GetString(this HttpSessionStateBase session, string key)
{
if (session == null)
{
return string.Empty;
}
var value = session[key];
if (value == null)
{
return string.Empty;
}
return Convert.ToString(value);
}
}
and then:
string value = Session.GetString("key");
Maybe this can ba an alternative?
object oKey = session["key"] ?? String.Empty;
string sKey = (string)oKey;
or
string sKey = session["key"] == null ? String.Empty : (string)session["key"]
public static class ObjectExtensions
{
public static string SafelyToString(this object o)
{
return o != null ? o.ToString() : string.Empty;
}
}
This will allow Session["key"].SafelyToString()
You will not however be able to discern between an empty string in the session variable and an expired session.
I would also advise using properties for that.
protected YourType PropertyName
{
get
{
if(Session["Sessionname"] != null)
{
return Session["Sessionname"] as YourType;
}
YourType newItem = new YourType();
// set vars
Session["Sessionname"] = newItem;
return newItem;
}
set
{
Session["Sessionname"] = value;
}
}
As you can see, I chose protected as access modifier. If you want you could put it in a public class and make the property static.
Or you can use class that derives from System.Web.UI.Page.
public class MyCustomBaseClass : System.Web.UI.Page
{
protected YourType PropertyName
{
// get and set like above
}
}
Now you can replace the inheritance in your content pages from System.Web.UI.Page to MyCustomBaseClass and can easily call this.PropertyName.
Here is a easy way to access Session in Extension method:
var loggedUser = (User)System.Web.HttpContext.Current.Session["User"];