I've written a custom attribute that I use on certain members of a class:
public class Dummy
{
[MyAttribute]
public string Foo { get; set; }
[MyAttribute]
public int Bar { get; set; }
}
I'm able to get the custom attributes from the type and find my specific attribute. What I can't figure out how to do is to get the values of the assigned properties. When I take an instance of Dummy and pass it (as an object) to my method, how can I take the PropertyInfo object I get back from .GetProperties() and get the values assigned to .Foo and .Bar?
EDIT:
My problem is that I can't figure out how to properly call GetValue.
void TestMethod (object o)
{
Type t = o.GetType();
var props = t.GetProperties();
foreach (var prop in props)
{
var propattr = prop.GetCustomAttributes(false);
object attr = (from row in propattr where row.GetType() == typeof(MyAttribute) select row).First();
if (attr == null)
continue;
MyAttribute myattr = (MyAttribute)attr;
var value = prop.GetValue(prop, null);
}
}
However, when I do this, the prop.GetValue call gives me a TargetException - Object does not match target type. How do I structure this call to get this value?
Your need to pass object itself to GetValue, not a property object:
var value = prop.GetValue(o, null);
And one more thing - you should use not .First(), but .FirstOrDefault(), because your code will throw an exception, if some property does not contains any attributes:
object attr = (from row in propattr
where row.GetType() == typeof(MyAttribute)
select row)
.FirstOrDefault();
You get array of PropertyInfo using .GetProperties() and call PropertyInfo.GetValue Method on each
Call it this way:
var value = prop.GetValue(o, null);
Related
I need to get the value of each property in an inputbuffer, I can get the name of the property but I can't get the value, I need to add the name and the value in a dictionary. This is my code:
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
Dictionary<string, string> body = new Dictionary<string, string>();
foreach (PropertyInfo inputColumn in Row.GetType().GetProperties())
{
if (!inputColumn.Name.EndsWith("IsNull"))
body.Add(inputColumn.Name, Row.GetType().GetProperty(inputColumn.Name).GetValue(Row).ToString() );
}
}
I got this exception: Object reference not set to an instance of an object
You just need to call GetValue on the inputColumn object like this:
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
Dictionary<string, string> body = new Dictionary<string, string>();
foreach (PropertyInfo inputColumn in Row.GetType().GetProperties())
{
if (!inputColumn.Name.EndsWith("IsNull"))
{
body.Add(inputColumn.Name,
(string)inputColumn.GetValue(Row));
}
}
}
You can simplify the whole method with a bit of Linq, and also make it generic like this:
public void ProcessRow<T>(T item)
{
var body = typeof(T) // Get the type
.GetProperties() // Get all properties
.Where(p => !p.Name.EndsWith("IsNull")) // Exclude properties ending with "IsNull"
.ToDictionary( // Return a dictionary
p => p.Name,
p => (string) p.GetValue(item));
}
You could also be even safer by making sure you only call properties that return string values with an additional Where clause:
.Where(p => p.PropertyType == typeof(string))
Or if you want to include other property types (e.g. int), then you will need to revert to using ToString:
p => p.GetValue(item).ToString()
That way you can reuse this method for other object types.
you should use variables for each method call, like var rowType = Row.GetType();.
Row.GetType().GetProperty(inputColumn.Name) can be replaced with inputColumn for example.
You can reuse variables in the same method and stack trace will show you the line where null reference is raised. Please check the stack trace, it will show you the method name that caused the error.
I suppose that .GetValue(Row) returns null.
I'm trying to access a property that is the same type of which is passed into a generic.
Look at the code:
class CustomClass
{
CustomProperty property {get; set;}
}
class CustomProperty
{
}
Main
{
// Create a new instance of my custom class
CustomClass myClass = new CustomClass();
// Create a new instance of another class that is the same type as myClass.property
CustomProperty myProp = new CustomProperty();
// Call the generic method
DynamicallyAccessPropertyOnObject<CustomProperty>(myProp, myClass);
}
private void DynamicallyAccessPropertyOnObject<T>(this T propertyToAccess, CustomClass class)
{
// I want to access the property (In class) that is the same type of that which is passed in the generic (typeof(propertyToAccess))
// TODO: I need help accessing the correct property based on the type passed in
}
If you can't see from the code. Basically I want to be able to pass in a something into a generic and then access the property on a class that is of the same type as the thing that was passed in.
Is there a good way to do this?
If you need clarification let me know...
You can use Reflection, and LINQ:
private static void DynamicallyAccessPropertyOnObject<T>()
{
var customClass = typeof(CustomClass);
var property = customClass
.GetProperties()
.FirstOrDefault(x => x.PropertyType == typeof(T));
}
If you are doing this for CustomClass only, you can remove both parameters.Then you can call it:
DynamicallyAccessPropertyOnObject<CustomProperty>();
If you want to generalize it, use two generic arguments:
private static void DynamicallyAccessPropertyOnObject<T, K>(K targetObj)
{
var targetType = targetObj.GetType();
var property = targetType
.GetProperties()
.FirstOrDefault(x => x.PropertyType == typeof(T));
if(property != null)
{
var value = (T)property.GetValue(targetObj);
}
}
Then call it:
DynamicallyAccessPropertyOnObject<CustomProperty,CustomClass>(myClass);
If there's only one such property you can do:
var prop = typeof(CustomClass).GetProperties().First(p => p.PropertyType == typeof(T));
object value = prop.GetValue(#class, null);
you can set the value with SetValue:
object valueToSet = ...
prop.SetValue(#class, valueToSet);
I have a Class with several ObservableCollections for different types. Now, I want to find the correct Collection for a given type via reflection, because I don't want to build an if-monster which I have to update every time I add another Collection.
This method was the first step:
public ObservableCollection<T> GetObservableCollectionForType<T>()
{
foreach (PropertyInfo info in this.GetType().GetProperties())
{
if (info.GetGetMethod() != null && info.PropertyType == typeof(ObservableCollection<T>))
return (ObservableCollection<T>)this.GetType().GetProperty(info.Name).GetValue(this, null);
}
return null;
}
Now, I need a second method, which accepts a concrete object as parameter and finds the correct Collection. Somehow like this:
public ObservableCollection<T> GetObservableCollectionFor(object sObject)
{
Type wantedType = sObject.GetType();
foreach (PropertyInfo info in this.GetType().GetProperties())
{
if (info.GetGetMethod() != null && info.PropertyType == ObservableCollection<wantedType>)
return this.GetType().GetProperty(info.Name).GetValue(this, null);
}
return null;
}
Any ideas how to realize this?
Update:
A working solution:
public object GetObservableCollectionFor(object sObject)
{
Type wantedType = sObject.GetType();
foreach (PropertyInfo info in this.GetType().GetProperties())
{
if (info.GetGetMethod() != null && info.PropertyType == typeof(ObservableCollection<>).MakeGenericType(new[]{wantedType}))
return this.GetType().GetProperty(info.Name).GetValue(this, null);
}
return null;
}
This will return the correct collection as object. I still don't know how to cast to the correct generic type, but casting to IList is enough for adding and removing.
When comparing the type of the property, it looks like you need to add a call to MakeGenericType() on the ObservableCollection type. Haven't tested this but maybe something like...
public ObservableCollection<T> GetObservableCollectionFor(object sObject)
{
Type wantedType = sObject.GetType();
foreach (PropertyInfo info in this.GetType().GetProperties())
{
if (info.GetGetMethod() != null && info.PropertyType == typeof(ObservableCollection<>).MakeGenericType(new[]{Type.GetType(wantedType)})
return (ObservableCollection<T>)this.GetType().GetProperty(info.Name).GetValue(this, null);
}
return null;
}
Edit
To avoid overhead boxing with value types, the above method definition could be improved by changing the parameter type from object to type T
public ObservableCollection<T> GetObservableCollectionFor(T sObject)
How can I access CssStyleCollection class properties ( most of all I interesting its key-value collection) using reflection?
// this code runns inside class that inherited from WebControl
PropertyInfo[] properties = GetType().GetProperties();
//I'am not able to do something like this
foreach (PropertyInfo property in properties)
{
if(property.Name == "Style")
{
IEnumerable x = property.GetValue(this, null) as IEnumerable;
...
}
}
Here's the syntax for getting the Style property via reflection:
PropertyInfo property = GetType().GetProperty("Style");
CssStyleCollection styles = property.GetValue(this, null) as CssStyleCollection;
foreach (string key in styles.Keys)
{
styles[key] = ?
}
Note that CssStyleCollection doesn't implement IEnumerable (it implements the indexing operator), so you can't cast it to that. If you want to get an IEnumerable, you could extract the keys using styles.Keys, and the values:
IEnumerable<string> keys = styles.Keys.OfType<string>();
IEnumerable<KeyValuePair<string,string>> kvps
= keys.Select(key => new KeyValuePair<string,string>(key, styles[key]));
I'm trying to get the names of the people in the below class. I can get the list of PropertyInfo just fine, indicating that People has Bob and Sally, but I can't get references to Bob and Sally. How do I do that?
public static class People
{
public static Person Bob { get; }
public static Person Sally { get; }
}
PropertyInfo[] properties = typeof(People).GetProperties();
foreach (PropertyInfo info in properties)
{
if (info.PropertyType == typeof(Person))
{
// how do I get a reference to the person here?
Person c = info.GetValue(?????, ?????) as Person;
if (null != c)
{
Console.WriteLine(c.Name);
}
}
}
edit changed null == c to null != c to get console.writeline to execute
Use:
Person c = (Person) info.GetValue(null, null);
if (c != null)
{
Console.WriteLine(c.Name);
}
The first null is for the target of the property - which is null because it's a static property. The second null is to say that there aren't any indexer arguments, because this is just a property, not an indexer. (They're the same kind of member to the CLR.)
I've changed the use of the result from an as to a cast as you're expecting the result to be a Person, given that you're already checked the property type.
I've then reversed the order of the operands for the comparison with null, as well as reversing the sense - you don't want to try to print out c.Name if you know that c is null! In C# the old C++ idiom of if (2 == x) to avoid accidental assignment is almost always pointless, as an if condition has to be a bool expression anyway. In my experience most people find the code more readable with the variable first and the constant second.
Here's the approach that I use, which I've thrown into its own method. This will return an array of objects that are all the instances that are statically available from the type you pass in. It should not matter if the original type is static or not.
using System;
using System.Linq;
using System.Reflection;
public static object[] RetrieveInstancesOfPublicStaticPropertysOfTypeOnType(Type typeToUse) {
var instances = new List<object>();
var propsOfSameReturnTypeAs = from prop in typeToUse.GetProperties(BindingFlags.Public | BindingFlags.Static)
where prop.PropertyType == typeToUse
select prop;
foreach (PropertyInfo props in propsOfSameReturnTypeAs) {
object invokeResult = typeToUse.InvokeMember(
props.Name,
BindingFlags.GetProperty,
null,
typeToUse,
new object[] { }
);
if (invokeResult != null) {
instances.Add(invokeResult);
}
}
return instances.ToArray();
}