Get string name of property using reflection - c#

There is a whole wealth of reflection examples out there that allow you to get either:
All properties in a class
A single property, provided you know the string name
Is there a way (using reflection, TypeDescriptor, or otherwise) to get the string name of a property in a class at runtime, provided all I have is an instance of the class and property?
I have an instance of the class with the property (as well as other properties) that I want to get the string name of (not the getter/setter). I need to do some work on that property using Reflection, but don't want to maintain code with hardcoded string names in case I refactor the property name. Thus, I want to programatically get the name of the property.
I know that I can easily get all the properties in a class using reflection and then get the name of each property. What I'm asking for is a function to give me name of a property, provided I pass it the instance of the property. In other words, how do I find the property I want from the PropertyInfo[] array returned to me from the class.GetType().GetProperty(myProperty) so that I can get the PropertyInfo.Name from it?

If you already have a PropertyInfo, then #dtb's answer of using PropertyInfo.Name is the right way. If, however, you're wanting to find out which property's code you're currently in, you'll have to traverse the current call stack to find out which method you're currently executing and derive the property name from there.
var stackTrace = new StackTrace();
var frames = stackTrace.GetFrames();
var thisFrame = frames[0];
var method = thisFrame.GetMethod();
var methodName = method.Name; // Should be get_* or set_*
var propertyName = method.Name.Substring(4);
If you don't have a PropertyInfo object, you can get that from a property expression, like this:
public static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
{
return (propertyExpression.Body as MemberExpression).Member.Name;
}
To use it, you'd write something like this:
var propertyName = GetPropertyName(
() => myObject.AProperty); // returns "AProperty"

With C# 6.0 (Visual Studio 2015), you can now use the nameof operator, like this:
var obj = new MyObject();
string propertyName = nameof(obj.Property);
string methodName = nameof(obj.Method);
string directPropertyName = nameof(MyObject.Property);
string directMethodName = nameof(MyObject.Method);

Use the PropertyInfo.Name class.

In case anyone needs it...here is the VB .NET version of the answer:
Public Shared Function GetPropertyName(Of t)(ByVal PropertyExp As Expression(Of Func(Of t))) As String
Return TryCast(PropertyExp.Body, MemberExpression).Member.Name
End Function
Usage:
Dim name As String = GetPropertyName(Function() (New myObject).AProperty)

I want to convert TKTS' answer syntax to C#:
public static string GetPropertyName<t>(Expression<Func<t>> PropertyExp)
{
return (PropertyExp.Body as MemberExpression).Member.Name;
}
and the usage of this code goes like the example as below:
string name = GetPropertyName(() => (new Tasks()).Title);
An exception could happen when all properties have null values, so care is needed when implementing this code.

The version provided by Jacob sometimes gives an exception due to the cast being invalid. This version solves that casting issue:
public static string GetPropertyName<T>(this Expression<Func<T>> propertyExpression)
{
ConstantExpression cExpr = propertyExpression.Body as ConstantExpression;
MemberExpression mExpr = propertyExpression.Body as MemberExpression;
if (cExpr != null)
return cExpr.Value.ToString();
else if (mExpr != null)
return mExpr.Member.Name;
else return null;
}

myClassInstance.GetType().GetProperties() gives you PropertyInfo instances for all public properties for myClassInstance's type. (See MSDN for documentation and other overloads.) ´PropertyInfo.Name´ is the actual name of the property. In case you already know the name of the property use GetProperty(name) to retrieve its PropertyInfo object (see MSDN again).

Related

C# Using reflection to get a an instantiated class given a string variable containing its name

In C# I have multiple instantiations of a class "CItems"(see below). I retrieve a string at run-time of the instantiation I want to use(in this case to call a public method-"addPropertyToList"). I know I have to use reflection but I can't seem to get it right.
CItems me = new CItems();
CItems conversations = new CItems();
string whichCItem = "me"
properties = <whichCItem>.addPropertyToList(properties, "FirstName", "Ken");
I tried many things like:
var myobject = this;
string propertyname = "me";
PropertyInfo property = myobject.GetType().GetProperty(propertyname);
object value = property.GetValue(myobject, null);
But that resulted in:
Object reference not set to an instance of an object. Because property ends up null.
Thanks for any help and please be gentle. I really have no idea what I am doing and I may have used some wrong terminology.
A simple Dictionary<T, U> might work for you.
Consider an example:
CItems me = new CItems();
CItems conversations = new CItems();
...
var dic = new Dictionary<string, CITems>();
doc.Add("me", me);
doc.Add("conversations", conversations);
...
//find object
CITems result= null;
dic.TryGetValue(searchString, out result);
PropertyInfo property = myobject.GetType().GetProperty(propertyname);
This is the correct approach for tretrieving the property identified by propertyname. You already know the type it is declared on, so you just use
var propertyInfo = CItems.GetProperty(propertyname)
to retrieve the class property. What you now need to do is set that property on the identified instance, so that you can call
propertyInfo.SetValue(<instance>, value);
How are your instances identified? Surely you are not giving back the name of the variable in which the object pointer is stored?
Is something like the following achievable?
IEnumerable<CItems> myItems = new { new CItem("me"), new CItem("conversations") }
void somemethod(string instanceName, string propertyname)
{
var instance = myItems.FirstOrDefault(item => item.Name == instanceName);
if(instance == null) return;
var propertyInfo = CItems.GetProperty(propertyname);
propertyInfo.SetValue(instance, value);
}

Get value of c# dynamic property via string

I'd like to access the value of a dynamic c# property with a string:
dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };
How can I get the value of d.value2 ("random") if I only have "value2" as a string? In javascript, I could do d["value2"] to access the value ("random"), but I'm not sure how to do this with c# and reflection. The closest I've come is this:
d.GetType().GetProperty("value2") ... but I don't know how to get the actual value from that.
As always, thanks for your help!
Once you have your PropertyInfo (from GetProperty), you need to call GetValue and pass in the instance that you want to get the value from. In your case:
d.GetType().GetProperty("value2").GetValue(d, null);
public static object GetProperty(object target, string name)
{
var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
return site.Target(site, target);
}
Add reference to Microsoft.CSharp. Works also for dynamic types and private properties and fields.
Edit: While this approach works, there is almost 20× faster method from the Microsoft.VisualBasic.dll assembly:
public static object GetProperty(object target, string name)
{
return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}
Dynamitey is an open source .net std library, that let's you call it like the dynamic keyword, but using the a string for the property name rather than the compiler doing it for you, and it ends up being equal to reflection speedwise (which is not nearly as fast as using the dynamic keyword, but this is due to the extra overhead of caching dynamically, where the compiler caches statically).
Dynamic.InvokeGet(d,"value2");
The easiest method for obtaining both a setter and a getter for a property which works for any type including dynamic and ExpandoObject is to use FastMember which also happens to be the fastest method around (it uses Emit).
You can either get a TypeAccessor based on a given type or an ObjectAccessor based of an instance of a given type.
Example:
var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");
var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");
dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");
var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");
typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");
typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");
Much of the time when you ask for a dynamic object, you get an ExpandoObject (not in the question's anonymous-but-statically-typed example above, but you mention JavaScript and my chosen JSON parser JsonFx, for one, generates ExpandoObjects).
If your dynamic is in fact an ExpandoObject, you can avoid reflection by casting it to IDictionary, as described at http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx.
Once you've cast to IDictionary, you have access to useful methods like .Item and .ContainsKey
The GetProperty/GetValue does not work for Json data, it always generate a null exception, however, you may try this approach:
Serialize your object using JsonConvert:
var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));
Then access it directly casting it back to string:
var pn = (string)z["DynamicFieldName"];
It may work straight applying the Convert.ToString(request)["DynamicFieldName"], however I haven't tested.
d.GetType().GetProperty("value2")
returns a PropertyInfo object.
So then do
propertyInfo.GetValue(d)
To get properties from dynamic doc
when .GetType() returns null, try this:
var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;
This is the way i ve got the value of a property value of a dinamic:
public dynamic Post(dynamic value)
{
try
{
if (value != null)
{
var valorCampos = "";
foreach (Newtonsoft.Json.Linq.JProperty item in value)
{
if (item.Name == "valorCampo")//property name
valorCampos = item.Value.ToString();
}
}
}
catch (Exception ex)
{
}
}
Some of the solutions were not working with a valuekind object that I obtained from a json string, maybe because I did not have a concrete type in my code that was similar to the object that I would obtain from the json string, so how I went about it was
JsonElement myObject = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(jsonStringRepresentationOfMyObject);
/*In this case I know that there is a property with
the name Code, otherwise use TryGetProperty. This will
still return a JsonElement*/
JsonElement propertyCode = myObject.GetProperty("Code");
/*Now with the JsonElement that represents the property,
you can use several methods to retrieve the actual value,
in this case I know that the value in the property is a string,
so I use the GetString method on the object. If I knew the value
was a double, then I would use the GetDouble() method on the object*/
string code = propertyCode.GetString();
That worked for me
In .Net core 3.1 you can try like this
d?.value2 , d?.value3
Similar to the accepted answer, you can also try GetField instead of GetProperty.
d.GetType().GetField("value2").GetValue(d);
Depending on how the actual Type was implemented, this may work when GetProperty() doesn't and can even be faster.
In case you have a dynamic variable such as a DapperRow for example you can first build up an ExpandoObject, then cast the Expando into an IDictionary<string, object>. From then on, getting a value via the name of a property is possible.
Helper method ToExpandoObject:
public static ExpandoObject ToExpandoObject(object value)
{
IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
IDictionary<string, object> expando = new ExpandoObject();
if (dapperRowProperties == null)
{
return expando as ExpandoObject;
}
foreach (KeyValuePair<string, object> property in dapperRowProperties)
{
if (!expando.ContainsKey(property.Key))
{
expando.Add(property.Key, property.Value);
}
else
{
//prefix the colliding key with a random guid suffixed
expando.Add(property.Key + Guid.NewGuid().ToString("N"), property.Value);
}
}
return expando as ExpandoObject;
}
Sample usage, I have marked in bold the casting which gives us access in the example, I have marked the important bits with the ** letters:
using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
foreach (var dynamicParametersForItem in dynamicParametersForItems)
{
var idsAfterInsertion = (await connection.QueryAsync<object>(sql, dynamicParametersForItem)).ToList();
if (idsAfterInsertion != null && idsAfterInsertion.Any())
{
**var idAfterInsertionDict = (IDictionary<string, object>) ToExpandoObject(idsAfterInsertion.First());**
string firstColumnKey = columnKeys.Select(c => c.Key).First();
**object idAfterInsertionValue = idAfterInsertionDict[firstColumnKey];**
addedIds.Add(idAfterInsertionValue); //we do not support compound keys, only items with one key column. Perhaps later versions will return multiple ids per inserted row for compound keys, this must be tested.
}
}
}
In my example, I look up a property value inside a dynamic object DapperRow and first convert the Dapper row into an ExpandoObject and cast it into a dictionary property bag as shown and mentioned in other answers here.
My sample code is the InsertMany method for Dapper extension I am working on, I wanted to grab hold of the multiple ids here after the batch insert.
Use dynamic with Newtonsoft.Json.JsonConvert.DeserializeObject:
// Get JSON string of object
var obj = new { value1 = "some", value2 = "random", value3 = "value" };
var jsonString = JsonConvert.SerializeObject(obj);
// Use dynamic with JsonConvert.DeserializeObject
dynamic d = JsonConvert.DeserializeObject(jsonString);
// output = "some"
Console.WriteLine(d["value1"]);
Sample:
https://dotnetfiddle.net/XGBLU1

How can I pass a property as a delegate?

This is a theoretical question, I've already got a solution to my problem that took me down a different path, but I think the question is still potentially interesting.
Can I pass object properties as delegates in the same way I can with methods? For instance:
Let's say I've got a data reader loaded up with data, and each field's value needs to be passed into properties of differing types having been checked for DBNull. If attempting to get a single field, I might write something like:
if(!rdr["field1"].Equals(DBNull.Value)) myClass.Property1 = rdr["field1"];
But if I've got say 100 fields, that becomes unwieldy very quickly. There's a couple of ways that a call to do this might look nice:
myClass.Property = GetDefaultOrValue<string>(rdr["field1"]); //Which incidentally is the route I took
Which might also look nice as an extension method:
myClass.Property = rdr["field1"].GetDefaultOrValue<string>();
Or:
SetPropertyFromDbValue<string>(myClass.Property1, rdr["field1"]); //Which is the one that I'm interested in on this theoretical level
In the second instance, the property would need to be passed as a delegate in order to set it.
So the question is in two parts:
Is this possible?
What would that look like?
[As this is only theoretical, answers in VB or C# are equally acceptable to me]
Edit: There's some slick answers here. Thanks all.
I like using expression trees to solve this problem. Whenever you have a method where you want to take a "property delegate", use the parameter type Expression<Func<T, TPropertyType>>. For example:
public void SetPropertyFromDbValue<T, TProperty>(
T obj,
Expression<Func<T, TProperty>> expression,
TProperty value
)
{
MemberExpression member = (MemberExpression)expression.Body;
PropertyInfo property = (PropertyInfo)member.Member;
property.SetValue(obj, value, null);
}
Nice thing about this is that the syntax looks the same for gets as well.
public TProperty GetPropertyFromDbValue<T, TProperty>(
T obj,
Expression<Func<T, TProperty>> expression
)
{
MemberExpression member = (MemberExpression)expression.Body;
PropertyInfo property = (PropertyInfo)member.Member;
return (TProperty)property.GetValue(obj, null);
}
Or, if you're feeling lazy:
public TProperty GetPropertyFromDbValue<T, TProperty>(
T obj,
Expression<Func<T, TProperty>> expression
)
{
return expression.Compile()(obj);
}
Invocation would look like:
SetPropertyFromDbValue(myClass, o => o.Property1, reader["field1"]);
GetPropertyFromDbValue(myClass, o => o.Property1);
(Adding a second answer because it's on a completely different approach)
To address your original problem, which is more about wanting a nice API for mapping named values in a datareader to properties on your object, consider System.ComponentModel.TypeDescriptor - an often overlooked alternative to doing reflective dirtywork yourself.
Here's a useful snippet:
var properties = TypeDescriptor.GetProperties(myObject)
.Cast<PropertyDescriptor>()
.ToDictionary(pr => pr.Name);
That creates a dictionary of the propertydescriptors of your object.
Now I can do this:
properties["Property1"].SetValue(myObject, rdr["item1"]);
PropertyDescriptor's SetValue method (unlike System.Reflection.PropertyInfo's equivalent) will do type conversion for you - parse strings as ints, and so on.
What's useful about this is one can imagine an attribute-driven approach to iterating through that properties collection (PropertyDescriptor has an Attributes property to allow you to get any custom attributes that were added to the property) figuring out which value in the datareader to use; or having a method that receives a dictionary of propertyname - columnname mappings which iterates through and performs all those sets for you.
I suspect an approach like this may give you the API shortcut you need in a way that lambda-expression reflective trickery - in this case - won't.
Ignoring whether this is useful in your specific circumstances (where I think the approach you've taken works just fine), your question is 'is there a way to convert a property into a delegate'.
Well, there kind of might be.
Every property actually (behind the scenes) consists of one or two methods - a set method and/or a get method. And you can - if you can get a hold of those methods - make delegates that wrap them.
For instance, once you've got hold of a System.Reflection.PropertyInfo object representing a property of type TProp on an object of type TObj, we can create an Action<TObj,TProp> (that is, a delegate that takes an object on which to set the property and a value to set it to) that wraps that setter method as follows:
Delegate.CreateDelegate(typeof (Action<TObj, TProp>), propertyInfo.GetSetMethod())
Or we can create an Action<TProp> that wraps the setter on a specific instance of TObj like this:
Delegate.CreateDelegate(typeof (Action<TProp>), instance, propertyInfo.GetSetMethod())
We can wrap that little lot up using a static reflection extension method:
public static Action<T> GetPropertySetter<TObject, T>(this TObject instance, Expression<Func<TObject, T>> propAccessExpression)
{
var memberExpression = propAccessExpression.Body as MemberExpression;
if (memberExpression == null) throw new ArgumentException("Lambda must be a simple property access", "propAccessExpression");
var accessedMember = memberExpression.Member as PropertyInfo;
if (accessedMember == null) throw new ArgumentException("Lambda must be a simple property access", "propAccessExpression");
var setter = accessedMember.GetSetMethod();
return (Action<T>) Delegate.CreateDelegate(typeof(Action<T>), instance, setter);
}
and now I can get a hold of a 'setter' delegate for a property on an object like this:
MyClass myObject = new MyClass();
Action<string> setter = myObject.GetPropertySetter(o => o.Property1);
That's strongly typed, based on the type of the property itself, so it's robust in the face of refactoring and compile-time typechecked.
Of course, in your case, you want to be able to set your property using a possibly-null object, so a strongly typed wrapper around the setter isn't the whole solution - but it does give you something to pass to your SetPropertyFromDbValue method.
No, there's nothing akin to method group conversions for properties. The best you can do is to use a lambda expression to form a Func<string> (for a getter) or an Action<string> (for a setter):
SetPropertyFromDbValue<string>(value => myClass.Property1 = value,
rdr["field1"]);
Worth mentioning you can do this with some reflection trickery..
something like...
public static void LoadFromReader<T>(this object source, SqlDataReader reader, string propertyName, string fieldName)
{
//Should check for nulls..
Type t = source.GetType();
PropertyInfo pi = t.GetProperty(propertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
object val = reader[fieldName];
if (val == DBNull.Value)
{
val = default(T);
}
//Try to change to same type as property...
val = Convert.ChangeType(val, pi.PropertyType);
pi.SetValue(source, val, null);
}
then
myClass.LoadFromReader<string>(reader,"Property1","field1");
As others have pointed, static reflexion is the way to go.
Those classes work out of the box :
http://www.codeproject.com/Articles/36262/Getting-Fun-with-Net-Static-Reflection.aspx

C# equivalent of typeof for fields

With reflection, you can look up a class from a string at run time, but you can also say typeof(Foo) and get compile time type checking, auto completion etc.
If what you want is a field not a class, you can look it up from a string at runtime, but if you want compile time type checking etc., is there anyway to say something like fieldof(Foo.Bar)? I know the name of both the class and the field in advance, and I want to be able to refer to the field at compile time rather than with a run-time string lookup.
edit: An example of what I want to use this for, say I've got a list of objects that may have been read from a database, and I want to display them in a DataGridView, but I only want displayed columns for certain fields. I'd like to write a method something like:
void DisplayData(object[] objs, params FieldInfo[] fields)
and be able to call it like
DisplayData(accounts, fieldof(Account.Name), fieldof(Account.Email));
That sort of idea.
You can get rid of string literals using expressions
public static PropertyInfo GetProperty<T>(Expression<Func<T, object>> expression)
{
MemberExpression memberExpression = null;
if (expression.Body.NodeType == ExpressionType.Convert)
{
memberExpression = ((UnaryExpression)expression.Body).Operand as MemberExpression;
}
else if (expression.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = expression.Body as MemberExpression;
}
return memberExpression.Member as PropertyInfo;
}
// usage:
PropertyInfo p = GetProperty<MyClass>(x => x.MyCompileTimeCheckedPropertyName);
Not for fields.
The closest you can get is a 'using alias' which allows you to specify alternative names for types:
e.g., using foo = System.Collections.Generic.List;

Pass a property of a Linq entity in a method to set and get result

I'm trying to pass in a property of a Linq entity to be used by my method. I can easily pass a property to be queried
Func<Entities.MyEntity, ResultType> GetProperty = ent => ent.Property;
However this returns ResultType and cannot be used to set the property.
I thought about using reflection to get a propertyInfo, but this will let me fetch the property but then I can't use Linq syntax to call my property. Is there any guru out there that knows how to do this?
I have a hunch I could do it by constructing a chunk of an expression tree and applying it onto the query...
I was really hoping to do something like:
var value = myQueryEntity.CallMagicFunction(); //typesafe
myQueryEntity.CallMagicFunction() = value; //typesafe
Indeed, an expression tree should work; for basic member access (a field/property directly off the object):
static MemberInfo ReadMember(LambdaExpression expr)
{
if(expr == null) throw new ArgumentNullException("expr");
MemberExpression me = expr.Body as MemberExpression;
if(me == null || !ReferenceEquals(me.Expression, expr.Parameters[0])) {
throw new ArgumentException("expr");
}
return me.Member;
}
with
Expression<Func<Customer, int>> func = c => c.Id;
MemberInfo member = ReadMember(func);
// for simplicity assume prop:
PropertyInfo prop = (PropertyInfo)member;
From there you can do pretty much anything; in particular you can get the get/set accessors (if you want to create a delegate), or use GetValue / SetValue.
Note that in .NET 4.0 you can set properties directly on an Expression (but the C# compiler doesn't add any extra support for this, so you'd need to write your own Expression by hand).

Categories

Resources