c# how to get input buffer property value as string - c#

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.

Related

C# iterate through class properties and add to list certain types

EDIT
I am sorry, my question was not clear. I want to add to the list not only the property name but its value
I want to iterate through all the properties of a class and find all properties of a certain type and add them to a list. The code I use to iterate is:
List<CustomAttribute> attributes = new List<CustomAttribute>();
PropertyInfo[] properties = typeof(CustomClass).GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(CustomAttribute))
{
//here I want to add property to list
}
}
Any ideas?
Thanks
public static List<PropertyInfo> PropertiesOfType<T>(this Type type) =>
type.GetProperties().Where(p => p.PropertyType == typeof(T)).ToList();
And you'd use it as follows:
var properties = typeof(CustomClass).PropertiesOfType<CustomAttribute>();
If what you need are the values of the properties of type T in a given instance then you could do the following:
public static List<T> PropertyValuesOfType<T>(this object o) =>
o.GetType().GetProperties().Where(p => p.PropertyType == typeof(T)).Select(p => (T)p.GetValue(o)).ToList();
And you'd use it as:
CustomClass myInstance = ...
var porpertyValues = myInstance.GetPropertyValuesOfType<CustomAttribute>();
Note that this just gives you the idea, you need to evaluate if dealing with properties with no getters is needed.
And last but not least, if you need the values and the property names, then you can build up a List of tuples to store the information:
public static List<Tuple<string, T>> PropertiesOfType<T>(this object o) =>
o.GetType().GetProperties().Where(p => p.PropertyType == typeof(T)).Select(p => new Tuple<string, T>(p.Name, (T)p.GetValue(o))).ToList();

Dynamically Access Properties by Type

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);

Using refection to get all properties and pass each property in method

I'm using simplemvvmtoolkit for validation (INotifyDataErrorInfo). Instead of me repeating my self over and over for each property within the view model, Id like to use reflection to get all the properties and validate them, I can't seem to figure out what to pass in the validateProperty method though.
private void ValidateInput()
{
var unitProperties = this.GetType().GetProperties()
.Where(x => x.CanRead);
foreach (var prop in unitProperties)
ValidateProperty(prop, prop.GetValue(this, null)); //????
//? ^ get errors here
}
ValidateProperty takes in:
protected virtual void ValidateProperty<TResult>(Expression<Func<TViewModel, TResult>> property, object value);
The problem is Expression<Func<TViewModel, TResult>> has absolutely no relation to PropertyInfo (the type returned by GetProperties). You'll also run into problems because the type of the result is not known at compile time.
The easiest solution would be to change ValidateProperty to accept a PropertyInfo:
protected virtual void ValidateProperty(PropertyInfo property, object value);
You could also convert the PropertyInfo to an Expression, but that's a bit more difficult:
var method = this.GetType().GetMethod("ValidateProperty");
foreach (var prop in unitProperties)
{
var parameter = Expression.Parameter(this.GetType(), "_");
var property = Expression.Property(parameter, prop);
var lambda = Expression.Lambda(property, parameter);
var genericMethod = method.MakeGenericMethod(prop.PropertyType);
genericMethod.Invoke(this, new object[] { lambda, prop.GetValue(this, null) });
}

Get value from custom attribute-decorated property?

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);

indexed switch statement, or equivalent? .net, C#

I want to build a method which accepts a string param, and an object which I would like to return a particular member of based on the param. So, the easiest method is to build a switch statement:
public GetMemberByName(MyObject myobj, string name)
{
switch(name){
case "PropOne": return myobj.prop1;
case "PropTwo": return myobj.prop2;
}
}
This works fine, but I may wind up with a rather large list... So I was curious if there's a way, without writing a bunch of nested if-else structures, to accomplish this in an indexed way, so that the matching field is found by index instead of falling through a switch until a match is found.
I considered using a Dictionary<string, something> to give fast access to the matching strings (as the key member) but since I'm wanting to access a member of a passed-in object, I'm not sure how this could be accomplished.
I'm specifically trying to avoid reflection etc in order to have a very fast implementation. I'll likely use code generation, so the solution doesn't need to be small/tight etc.
I originally was building a dictionary of but each object was initializing it. So I began to move this to a single method that can look up the values based on the keys- a switch statement. But since I'm no longer indexed, I'm afraid the continuous lookups calling this method would be slow.
SO: I am looking for a way to combine the performance of an indexed/hashed lookup (like the Dictionary uses) with returning particular properties of a passed-in object. I'll likely put this in a static method within each class it is used for.
Here's a quick mockup of something that could work for any class (using reflection rather than a switch statement):
public static object GetMemberByName<T>(T obj, string name)
{
PropertyInfo prop = typeof(T).GetProperty(name);
if(prop != null)
return prop.GetValue(obj, null);
throw new ArgumentException("Named property doesn't exist.");
}
Or an Extension Method version (which will still work on any object type):
public static object GetMemberByName<T>(this T obj, string name)
{
PropertyInfo prop = typeof(T).GetProperty(name);
if(prop != null)
return prop.GetValue(obj, null);
throw new ArgumentException("Named property doesn't exist.");
}
Obviously there's some additional error checking you might want to do, but this would be a start.
I also returned the type object from the methods for a reason. This allows the caller to handle casting the value however they see fit (if they need to cast at all).
Here's an easy way you can use a dictionary:
Dictionary<string, Func<MyObject, object>> propertyNameAssociations;
private void BuildPropertyNameAssociations()
{
propertyNameAssociations = new Dictionary<string, Func<MyObject, object>>();
propertyNameAssociations.Add("PropOne", x => x.prop1);
propertyNameAssociations.Add("PropTwo", x => x.prop2);
}
public object GetMemberByName(MyObject myobj, string name)
{
if (propertyNameAssociations.Contains(name))
return propertyNameAssociations[name](myobj);
else
return null;
}
There are a few options you can try.
Option 1: Have the object store the property values dynamically.
public GetMemberByName(MyObject myobj, string name)
{
return myobj.GetProperty(name);
}
public class MyObject
{
private Dictionary<string, object> m_Properties = new Dictionary<string, object>();
public object GetProperty(string name)
{
return m_Properties[name];
}
public void SetProperty(string name, object value)
{
m_Properties[name] = value;
}
public object Prop1
{
get { return GetProperty("PropOne"); }
set { SetProperty("PropOne", value); }
}
public object Prop2
{
get { return GetProperty("PropTwo"); }
set { SetProperty("PropTwo", value); }
}
}
Option 2: Use reflection.
public GetMemberByName(MyObject myobj, string name)
{
return typeof(MyObject).GetProperty(name).GetValue(obj, null);
}
Option 3: Leave it the way it is.
This is a reasonable option because switch statements on string data types will be converted to a Dictionary lookup once the number case statements reaches a certain threshold. That threshold is 7 on the C# 3.0 compiler. So the lookup will be O(1) no matter how many case statements there are. It will not scan through each one.
You can use reflection to get a property dynamically at runtime. Here is a snippet from a little relection utility i wrote. This is written as an extension method which would easily allow you to get a property from your class instance
myInstance.GetProperty<string>("Title"); // Replace 'string' with the proper return value.
The code:
public static class ReflectionExtensions
{
private const BindingFlags DefaultFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
public static T GetProperty<T>(this object instance, string propertyName)
{
PropertyInfo property = GetPropertyInfo(instance, propertyName);
if (property == null)
{
var message = string.Format("The Type, '{0}' does not implement a '{1}' property", instance.GetType().AssemblyQualifiedName, propertyName);
throw new NotImplementedException(message);
}
return (T)property.GetValue(instance, null);
}
private static PropertyInfo GetPropertyInfo(object instance, string propertyName)
{
Type type = instance.GetType();
return type.GetProperty(propertyName, DefaultFlags);
}
}
Well, assuming that the Name matches the actual name of the property (unlike your example), this would probably be best handled through reflection.
You cant do it with an index, but you could use reflection.
You may want to try using something like this.
private static readonly Dictionary<Type, Dictionary<string, PropertyInfo>> _cache = new Dictionary<Type,Dictionary<string,PropertyInfo>>();
public static T GetProperty<T>(object obj, string name)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
else if (name == null)
{
throw new ArgumentNullException("name");
}
lock (_cache)
{
var type = obj.GetType();
var props = default(Dictionary<string, PropertyInfo>);
if (!_cache.TryGetValue(type, out props))
{
props = new Dictionary<string, PropertyInfo>();
_cache.Add(type, props);
}
var prop = default(PropertyInfo);
if (!props.TryGetValue(name, out prop))
{
prop = type.GetProperty(name);
if (prop == null)
{
throw new MissingMemberException(name);
}
props.Add(name, prop);
}
return (T)prop.GetValue(obj, null);
}
}

Categories