Get attribute of property knowing what it is - c#

want to do something very simple and that is getting the attribute of a property. Now I know how to do this via PropertyInfo etc but I know the property I want to get the attribute of so is it possible to do something like:
MyAttribute attr = (MyAttribute)customer.Forename;
Ideally want to avoid reflection. Only way I can think of is doing a linq statement like:
PropertyInfo pi = typeof(Customer).GetProperties().Where(x => x.Name == "Forename").FirstOrDefault();
MyAttribute attri = (MyAttribute)Attribute.GetCustomAttribute(pi, typeof(MyAttribute));
Don't like this as I am having to do a string comparison on the property name :(
Considering I know the property I want to get the attribute of I thought there might be an easier way?

Kzu wrote a piece of code to allow strongly typed reflection.
See a blog post here: http://blogs.clariusconsulting.net/kzu/linq-beyond-queries-strong-typed-reflection/
You can now get it as a NuGet package (NETFx Reflector):
http://nuget.org/packages/netfx-Reflector
// Void static method
MethodInfo cw = Reflect.GetMethod(() => Console.WriteLine);
// Instance void method
MethodInfo mi = Reflect<IView>.GetMethod(v => v.Show);
// Boolean returning instance method
MethodInfo pi = Reflect<IViewModel>.GetMethod<bool>(v => v.Save);

Related

Get a property name from a lambda expression *without* an object instance

Asp.net MVC introduced the EditorFor method on the Html generic class. It allows you to write code that succinctly identifies a field of the view model. In this case the page this code is from must have a view model of some type that has a StudentId property or else this won't work.
#Html.EditorFor(m => m.StudentId)
The signature of the EditorFor property is something like this.
EditorFor<TModel,TValue>(HtmlHelper<TModel>, Expression<Func<TModel,TValue>>)
The method is defined on a generic type that knows the type of the TModel. So the lambda expression can be as simple as m => m.StudentId and we all know that the type of m is whatever TModel is. In this case it is the page's view model.
I would like to be able to write similar code, without knowing what type the property is defined on. I'd like to be able to write...
#Html.EditorFor(M.StudentId) // here M is a type not a lambda parameter
#Html.EditorFor(X.Y) // here X is a type not a lambda parameter
I'd like to be able to specify an arbitry type, and an arbitrary parameter, and have the method called with something that identifies both. For example if the method were called with a PropertyInfo then I could see both the property and the type it was defined on, both.
Said another way... In the same way that nameof(X.Y) gives a string "Y" for any arbitrary type X, I'd like an expression that gives something like a PropertyInfo too. Maybe property(X.Y) and you get back the PropertyInfo of the property Y from the type X.
You can use a property expression the same way as EditorFor. You can do this without an instance.
The one difference is you'll have to specify the type of the expression's parameter to tell the compiler what the object type is. So instead of
EditorFor( x => x.Name ); //Specifies a property but not a type
...your expression would look like this:
EditorFor( (MyType x) => x.Name ); //Specifies property and the type it belongs to
You can accomplish this with a short method like this one:
static PropertyInfo GetPropertyInfo<TIn, TOut>(Expression<Func<TIn, TOut>> expression)
{
var memberExp = expression.Body as MemberExpression;
return memberExp?.Member as PropertyInfo;
}
And then you can do this:
var p1 = GetPropertyInfo((string s) => s.Length);
Console.WriteLine("{0}.{1}", p1.DeclaringType.FullName, p1.Name);
var p2 = GetPropertyInfo((DateTime d) => d.Minute);
Console.WriteLine("{0}.{1}", p2.DeclaringType.FullName, p2.Name);
var p3 = GetPropertyInfo((Stream s) => s.CanSeek);
Console.WriteLine("{0}.{1}", p3.DeclaringType.FullName, p3.Name);
Output:
System.String.Length
System.DateTime.Minute
System.IO.Stream.CanSeek
Notice that we never needed any instances.

Can I get PropertyInfo for a field or property in a class without using reflection?

I have tried searching around using Expressions but not able to find something by which I can access the fields or properties of a class without using reflection.
Basically, I will get a string at runtime, and I know that that string will be a property of the class, but I need to validate that it indeed is a property inside that class.
e.g. If I have a class:
class Test { string a; public string b {get;set;} }
I get the string values a and b at runtime and I need to verify that they exist inside the class Test
What I know till now from researching is that I can do:
string one = "a";
string two = "b";
PropertyInfo result1 = typeof(Test).GetProperty(one);
PropertyInfo result2 = typeof(Test).GetProperty(two);
But this code is using reflection. I want to know if there is some way I can do this without using reflection?
Can I do this using Expressions?
With an expression, you can get the a PropertyInfo the following way:
Test t = new Test();
t.b = "sadf";
Expression<Func<string>> exp = () => t.b;
var memExp = exp.Body as MemberExpression;
MemberInfo member = memExp.Member;
PropertyInfo property = (PropertyInfo)member;
Console.WriteLine(property.GetValue(t));
This will output the value of your property of your variable (sadf in the example). But what do you want to achieve? Why don't you collect the PropertyInfo from the Type? Because it is quite possible that under the hood, this code will use reflection the very same way you did (the same as LINQ still uses loop, but the programer just doesn't see it).

Use property Created by Property Info and use in Lambda

I have a method with parameter as object, the object is a string value of properties in DocumentModel class
private PropertyInfo SortingListView(object obj)
{
return typeof(DocumentModel).GetProperty(obj.ToString());
}
I want the PropertyInfo to be used in a lambda expression like below:
var SortedDocuments=Documents.OrderByDescending(x => SortingListView(obj));
But it's not working. Any suggestions? Or any better way? Am I doing it correctly? Please help.
If I got it right, you're trying to sort your list of DocumentModel by whatever property is passed. The way you're currently doing it is wrong because you're actually sorting them by PropertyInfo of your property and since all objects are of the same type this basically does nothing. What you need to do actually is something like this:
private object SortingListView<T>(T obj, string propertyName)
{
return typeof(T).GetProperty(propertyName).GetValue(obj);
}
You can call it this way:
var obj = "SomePropertyName";
var sortedDocuments = Documents.OrderByDescending(x => SortingListView(x, obj));
If you're only going to use it here, you could also do it like this:
var obj = "SomePropertyName";
var sortedDocuments = Documents.OrderByDescending(x =>
typeof(DocumentModel).GetProperty(obj).GetValue(x));
This way you don't need extra method, you have all the logic inside your lambda expression.

Extract a generic value using reflection

I have the following interface in my project.
public interface Setting<T>
{
T Value { get; set; }
}
Using reflection, I would like to examine properties that implement this interface and extract Value.
So far I have written this, which successfully creates a list of properties that implement Setting.
var properties = from p in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
where p.PropertyType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IAplSetting<>))
select p;
Next I would like to do this: (Please ignore the undefined variables, you can assume that they really do exist in my actual code.)
foreach (var property in properties)
{
dictionary.Add(property.Name, property.GetValue(_theObject, null).Value);
}
The problem is that GetValue returns an object. In order to access Value, I need to be able to cast to Setting<T>. How would I get Value and store it, without needing to know the exact type of T?
You could continue this approach with one more level of indirection:
object settingsObject = property.GetValue(_theObject, null);
dictionary.Add(
property.Name,
settingsObject.GetType().GetProperty("Value")
.GetValue(settingsObject, null));
If you're using dynamic (re: your comment about ExpandoObject), this can be much simpler:
dynamic settingsObject = property.GetValue(_theObject, null);
dictionary.Add(property.Name, settingsObject.Value);

Using reflection with generic types and implicit conversions

I'm trying to use reflection to set properties on some OpenXML types (e.g. Justification). Assigning a value by enumerating all possibilities is straight-forward:
// attr is an XmlAttribute, so .Name and .Value are Strings
if (attr.Name == "Val")
{
if (element is Justification)
{
((Justification)element).Val = (JustificationValues)Enum.Parse(typeof(JustificationValues), attr.Value);
return;
}
else
{
// test for dozens of other types, such as TabStop
}
}
What makes this difficult to do via reflection is:
1) The type of the Val property is EnumValue<T>, so I don't know how to extract the type to pass as the first argument to Enum.Parse.
2) There is an implicit conversion from the actual enumeration type to the EnumValue<> type, which I don't know how to invoke with reflection.
I would like the code to end up looking something like:
PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = ConvertToPropType(pInfo.PropertyType, attr.Value); /* this
would return an instance of EnumValue<JustificationValues> in this case */
pInfo.SetValue(element, value, null);
How do I implement ConvertToPropType? Or is there a better solution?
Thanks
Edit:
I got a solution working using Earwicker's suggestion, but it relies on the convenient fact that the enumeration's type name can be derived from the node's type name ("Justification" -> "JustificationValues"). I'm still curious how to solve this in the general case, though.
Edit2:
GetGenericArguments got me the rest of the way there. Thanks.
If the attribute value is just a string, I assume you already have some way of figuring out that the string identifies a value from a specific enumeration. In your example you have it hard-coded, so I'm not sure if that's what you want or what you want to change.
Assuming you know it's an enumeration, and you know which enumeration, you already know how to get an object containing a boxed value of the right enum type, as in your snippet.
Now if I assume EnumValue<T> has a constructor that takes a T.
Type genericType = typeof(EnumValue<>);
Type concreteType = genericType.MakeGenericType(typeof(JustificationValues));
Now concreteType is the type EnumValue<JustificationValues>.
From that you can get a constructor, hopefully one that takes a JustificationValues parameter, and Invoke it.
Update
Ahh, I see what you're doing now. You use the XML attribute name to pick a C# property. You need to be able to detect whether that property is of a type EnumValue<T>, and find out what T is.
PropertyInfo p = // ... get property info
Type t = p.GetType();
if (t.IsGenericType &&
t.GetGenericTypeDefinition == typeof(EnumValue<>))
{
Type e = t.GetGenericArguments()[0]; // get first (and only) type arg
// e is the enum type...
Give that a try.
.Net 4.0 adds support to do a late bound implict or explict conversion. This is simplified in the open source framework ImpromptuInterface with it's static method called InvokeConvert. In your ideal example it would work like this:
PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = Impromptu.InvokeConvert(attr.Value, pInfo.PropertyType);
pInfo.SetValue(element, value, null);
This might only work with basic types but it was good enough for what I'm doing
PropertyInfo pInfo = element.GetType().GetProperty(attr.Name);
Object value = System.Convert.ChangeType(attr.Value, pInfo.PropertyType);
pInfo.SetValue(element, value, null);

Categories