My class has a bunch of nullable double properties. At run time some of them have 0 value and i am going to set them null before sending action. I know that we can use a foreach statement to iterate through a collection which has been placed inside a class so i hope use the same technique for this problem. As i said in this case i am not working with a collection so
Implementing the IEnumerable is a kind of meaningless idea.
Is there any way to move among the members of class ?
I have tried this
Class1 c=new Class1(){Age = 12,Family = "JR",Name = "MAX"};
foreach (string member in c)
{
Console.WriteLine(member);
}
Console.ReadKey();
Implementing the IEnumerable
public IEnumerator GetEnumerator()
{
// ?!
}
You can use Reflection and Linq for this
using System.Reflection;
...
private static void ApplyNullsForZeroes(Object value) {
if (null == value)
return; // Or throw exception
var props = value.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead && p.CanWrite)
.Where(p => p.PropertyType == typeof(Nullable<Double>));
foreach (var p in props)
if (Object.Equals(p.GetValue(value), 0.0))
p.SetValue(value, null);
}
Test
public class MyClass {
public MyClass() {
Value = 0.0;
}
public Double? Value {
get;
set;
}
}
...
MyClass test = new MyClass();
ApplyNullsForZeroes(test);
if (test.Value == null)
Console.Write("It's null now");
You have to use Reflection, please look at
How to get the list of properties of a class?
I added a new double? property at your class.
class Class1
{
public int Age { get; set; }
public string Family { get; set; }
public string Name { get; set; }
public double? d { get; set; }
}
[Test]
public void MyTest()
{
Class1 c = new Class1() { Age = 12, Family = "JR", Name = "MAX" };
foreach (var prop in c.GetType().GetProperties().Where(x => x.PropertyType == typeof(double?)))
{
Console.WriteLine("{0}={1}", prop.Name, prop.GetValue(c));
prop.SetValue(c, (double?)null); // set null as you wanted
}
}
As you said you have properties, so why not use them as a Property?
Use condition in get. Return null while getting the value of property:
get
{
return Age == 0 ? null : Age; //supposing "Age" is double in case to show an example
}
Related
So I am using reflection to loop through the properties of one object and populating the values on a different object with properties of the same name. This works great but the problem comes when the property type is a collection. I want to be able to loop through each of the objects in the source collection and populate the same list with objects in the source collection.
public class SourceMessage
{
public string Name { get; set; }
public int Version { get; set; }
public IList<ValueDefinition> Values { get; set; }
}
public class ValueDefinition
{
public string Name { get; set; }
public string Value { get; set; }
}
public class TargetObject
{
public TargetObject()
{
Values = new List<TargetValueDefinition>();
}
public string Name { get; set; }
public int Version { get; set; }
public IList<TargetValueDefinition> Values { get; set; }
}
public class TargetValueDefinition
{
public string Name { get; set; }
public string Value { get; set; }
}
Then I use Reflection to populate the target from the source.
public static void PopulateFromMessage<T, TS>(ref T targetEntity, TS message)
{
var sourceType = typeof(TS);
var targetType = typeof(T);
foreach (var targetPropInfo in targetType.GetProperties())
{
if (sourceType.GetProperty(targetPropInfo.Name) != null)
{
var obj = sourceType.GetProperty(targetPropInfo.Name);
if (obj.PropertyType.Namespace == "System.Collections.Generic")
{
//var x = targetType.GetProperty(targetPropInfo.Name);
//PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
continue;
}
targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
}
}
}
So calling this would be like this:
private void DenormalizeMessage(SourceMessage message)
{
var newTargetObject = new TargetObject();
PopulateFromMessage(ref newTargetObject , message);
}
I can identify when the property is a collection but am uncertain of how to create new TargetValueDefinitions and populate them with the values from ValueDefinitions. In the end it is pretty much a copy of the SourceMessage in the form of a TargetObject.
This all stems from receiving messages and transforming them into objects with the same property names.
If your problem is iterating through items contained inside a single property when it is a collection, then the key would be to read the property value into a dynamic variable and not an object variable that is by default, this way you could use a foreach for it.
dynamic propVal = inputProperty.GetValue(item);
foreach (var subItem in propVal)
{
//do your stuff
}
Disclaimer: This is extremely unsafe to do and makes a lot of assumptions but it should puth you on the right path.
Change you method to this:
public static void PopulateFromMessage<T, TS>(T targetEntity, TS message)
{
var sourceType = typeof (TS);
var targetType = typeof (T);
foreach (var targetPropInfo in targetType.GetProperties())
{
if (targetPropInfo.PropertyType.IsGenericType)
{
if (targetPropInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>))
{
var originalList = sourceType.GetProperty(targetPropInfo.Name).GetValue(message) as IList;
if (originalList != null)
{
var argumentType = targetPropInfo.PropertyType.GetGenericArguments();
var listType = typeof (List<>);
var concreteType = listType.MakeGenericType(argumentType);
var newList = Activator.CreateInstance(concreteType) as IList;
foreach (var original in originalList)
{
var targetValue = Activator.CreateInstance(argumentType[0]);
// do this yourself. Here we're converting ValueDefinition to TargetValueDefinition
// targetValue.Fill(original);
}
targetPropInfo.SetValue(targetEntity, newList);
}
}
}
else
{
if (sourceType.GetProperty(targetPropInfo.Name) != null)
{
var obj = sourceType.GetProperty(targetPropInfo.Name);
if (obj.PropertyType.Namespace == "System.Collections.Generic")
{
//var x = targetType.GetProperty(targetPropInfo.Name);
//PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
continue;
}
targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
}
}
}
}
You should create a interface for each class (implement the methods and properties on interface) and implement it in each class. After, in function PopulateFromMessage should specify the interface allowed in method, with this you can use directly the properties of class with T and TS generic types.
Normally when I want for example to find the first or default item of a List I use this way:
myList.SingleOrDefault(x=>x.MyPropery01 == "myCondition");
However, I would like to know if it is possible, for example by reflection, if I set the the property MyProperty dynamically, something like:
myList.SingleOrDefault(x=>x.GetType().GetProperty("MyProperty01") == "myCondition");
Because sometimes I need to search for MyProperty01, sometimes for MyProperty02, MyProperty03, etc..
EDIT: in visual studio I get this error:
"Operator '==' can't be applied to operands of type System.reflection.PropertyInfo and string".
Yeah you can do that. You were pretty close, here is a demo you can drop in linqpad. Note that the important part is
Single(l => l.GetType().GetProperty(prop).GetValue(l).ToString() == "Condition")
void Main()
{
var myList = Enumerable.Range(0,10).Select(i => new Xmas(i,"name"+i)).ToList();
string prop = "name";
Console.WriteLine(myList.Single(l => l.GetType().GetProperty(prop).GetValue(l).ToString() == "name6").name);
}
public class Xmas
{
public int id { get; set; }
public string name { get; set; }
public Xmas( int id, string name )
{
this.id = id;
this.name = name;
}
}
Working example:
public class Apple
{
public string Color { get; set; }
}
public List<Apple> ApplesList {get;set;}
public void Process()
{
PropertyInfo pi = typeof(Apple).GetProperty("Color");
ApplesList = ApplesList.Where(r => (string)pi.GetValue(r) == "Red").ToList();
}
You could also write an Extension method, that allow to get the property on every object, returning null when it doesn't exist, or doesn't have a GetMethod. You could keep a Cache if you want
public static class ObjectExtension
{
static IDictionary<KeyValuePair<Type, string>, PropertyInfo> propertyCache = new Dictionary<KeyValuePair<Type, string>, PropertyInfo>();
public static object GetProperty(this object source, string propertyName, bool useCache = true)
{
if (source == null)
{
return null;
}
var sourceType = source.GetType();
KeyValuePair<Type, string> kvp = new KeyValuePair<Type, string>(sourceType, propertyName);
PropertyInfo property = null;
if (!useCache || !propertyCache.ContainsKey(kvp))
{
property = sourceType.GetProperty(propertyName);
if (property == null)
{
return null;
}
var get = property.GetGetMethod();
if (get == null)
{
return null;
}
if (useCache)
{
propertyCache.Add(kvp, property);
}
}
else
{
property = propertyCache[kvp];
}
return property.GetValue(source, null);
}
public static T GetProperty<T>(this object source, string propertyName)
{
object value = GetProperty((object)source, propertyName);
if (value == null)
{
return default(T);
}
return (T)value;
}
}
A small test class could then be:
public class Item
{
public string MyProperty { get; set; }
public string MyProperty3 { get; set; }
public string MyProperty2 { protected get; set; }
public Item()
{
MyProperty = "Test propery";
MyProperty3 = "Test property 3";
MyProperty2 = "Yoohoo";
}
}
With a main class for testing
class Program
{
static void Main(string[] args)
{
Item item = new Item();
for (int x = 0; x < 4; x++)
{
string key = "MyProperty" + (x > 0 ? x.ToString() : "");
string value = item.GetProperty<string>(key);
Console.WriteLine("Getting {0} = {1}", key, value);
}
Console.ReadLine();
}
}
which gives the expectable output of:
Getting MyProperty = Test propery
Getting MyProperty1 =
Getting MyProperty2 =
Getting MyProperty3 = Test property 3
I have several get properties that I would like to be able to loop through like an array of functions. I would like to be able to do something like this
public int prop1 { get; }
public string prop2 { get; }
public int[] prop3 { get; }
public int prop4 { get; }
public string prop5 { get; }
public string prop6 { get; }
Func<var> myProperties = { prop1, prop2, prop3, prop4, prop5, prop6 };
ArrayList myList = new ArrayList();
foreach( var p in myProperties)
{
myList.Add(p);
}
This code is very broken, but I think it conveys the idea of what I would like to be able to do. Anyone know how I can achieve this?
You could use reflection to access the properties within your type:
class MyType
{
public int prop1 { get; }
public string prop2 { get; }
public int[] prop3 { get; }
public int prop4 { get; }
public string prop5 { get; }
public string prop6 { get; }
public List<string> GetAllPropertyValues()
{
List<string> values = new List<string>();
foreach (var pi in typeof(MyType).GetProperties())
{
values.Add(pi.GetValue(this, null).ToString());
}
return values;
}
}
Note that reflection is slow and you shouldn’t use this if there is a better way. For example when you know that there are only 6 properties, just go through them individually.
If you know all the properties you want to loop through already, then you can try this
List<Reflection.PropertyInfo> myProperties = new List()<object>
{
typeof(SomeType).GetProperty("prop1"),
typeof(SomeType).GetProperty("prop2"),
typeof(SomeType).GetProperty("prop3"),
typeof(SomeType).GetProperty("prop4"),
typeof(SomeType).GetProperty("prop5"),
typeof(SomeType).GetProperty("prop6")
};
foreach(var p in myProperties)
{
var value = p.GetValue(someObject, new object[0]);
myList.Add(p);
}
If not, you can use something like this:
var myProperties =
from pi in someObject.GetType().GetProperties()
select new
{
pi.Name,
Value = pi.GetValue(object, new object[0])
};
foreach(var p in myProperties)
{
myList.Add(p.Value);
}
You can try to use GetProperties
GetProperties Documentation
Example:
PropertyInfo[] myPropertyInfo;
// Get the properties of 'Type' class object.
myPropertyInfo = Type.GetType("System.Type").GetProperties();
Console.WriteLine("Properties of System.Type are:");
for (int i = 0; i < myPropertyInfo.Length; i++)
{
Console.WriteLine(myPropertyInfo[i].ToString());
}
Further Info:
The example for GetProperties with flags is really nice, and it can be useful for you if you want to access to a specific subset of Properties (Like only the Public Ones)
The code is not so far from working. The myProperties variable should be an array, and you need to create functions that read from the properties. (The property getter is actually implemented as a function, but you can't call it as a function or get a reference to it.) Then you use them by calling them.
public class MyClass {
public int prop1 { get; set; }
public string prop2 { get; set; }
public int[] prop3 { get; set; }
public int prop4 { get; set; }
public string prop5 { get; set; }
public string prop6 { get; set; }
public ArrayList GetProperties() {
Func<object>[] myProperties = {
() => prop1, () => prop2, () => prop3,
() => prop4, () => prop5, () => prop6
};
ArrayList myList = new ArrayList();
foreach (var p in myProperties) {
myList.Add(p());
}
return myList;
}
}
If you're needing your Properties in an Array, because you're needing to (as I did) Set and/or Get several related (and same-Typed) Properties, here's what you can do. I know Reflection is "'slow'", but for my use cases, the duplicate code (and therefore error chance) reduction benefits far outweigh any "'slowness'" (which are insignificant) due to Reflection. This does not handle Indexed Properties, but a version to so can easily be created from this.
`
public class MyClass
{
private string[] myBoolPropertyNames =
{
nameof(MyBool1Property),
nameof(MyBool2Property)
}; // MyBoolPropertyNames =
private MyClass()
{
foreach (var propertyName in myBoolPropertyNames)
{
ReflectionHelper.SetPropertyValue
(
parentObject: this,
propertyName: propertyName,
untypedPropertyValue: true
); // SetPropertyValue
} // foreach (var propertyName in myBoolPropertyNames)
foreach (var propertyName in myBoolPropertyNames)
{
bool boolPropertyValue = ReflectionHelper.GetPropertyValue<bool>
(
parentObject: this,
propertyName: propertyName
); // SetPropertyValue
Console.WriteLine($"Property '{propertyName}' value: {boolPropertyValue}");
} // foreach (var propertyName in myBoolPropertyNames)
}
public bool MyBool1Property { get; set; }
public bool MyBool2Property { get; set; }
} // MyClass
`
`
public class ReflectionHelper
{
public static PropertyType GetPropertyValue<PropertyType>
(
object parentObject,
string propertyName
)
{
if (parentObject == null)
{
throw new ArgumentException
(
$"Missing '{nameof(parentObject)}'."
);
} // if (parentObject == null)
PropertyInfo propertyInfo = parentObject.GetType().GetProperty(propertyName);
if (propertyInfo == null)
{
throw new ArgumentException
(
"No PropertyInfo found for Property: " + propertyName
);
} // if (propertyInfo == null)
object untypedPropertyValue = propertyInfo.GetValue(obj: parentObject);
Type propertyType =
(
Nullable.GetUnderlyingType(propertyInfo.PropertyType)
?? propertyInfo.PropertyType
); // propertyType =
object typedPropertyValue =
(
(untypedPropertyValue == null)
? null
: Convert.ChangeType(untypedPropertyValue, propertyType)
); // typedPropertyValue =
return (PropertyType)typedPropertyValue;
} // GetPropertyValue
public static void SetPropertyValue
(
object parentObject,
string propertyName,
object untypedPropertyValue
)
{
if (parentObject == null)
{
throw new ArgumentException
(
$"Missing '{nameof(parentObject)}'."
);
} // if (parentObject == null)
PropertyInfo propertyInfo = parentObject.GetType().GetProperty(propertyName);
if (propertyInfo == null)
{
throw new ArgumentException
(
"No PropertyInfo found for Property: " + propertyName
);
} // if (propertyInfo == null)
Type propertyType =
(
Nullable.GetUnderlyingType(propertyInfo.PropertyType)
?? propertyInfo.PropertyType
); // propertyType =
object typedPropertyValue =
(
(untypedPropertyValue == null)
? null
: Convert.ChangeType(untypedPropertyValue, propertyType)
); // typedPropertyValue =
propertyInfo.SetValue
(
obj: parentObject,
value: typedPropertyValue
); // propertyInfo.SetValue
} // SetPropertyValue
} // ReflectionHelper
`
You can use an array buffer and get all prop from it. in this way you can get and set very fast:
public object[] buf = new object[5];
public int prop1 { get => buf[0]; }
public string prop2 { get => buf[1]; }
public int[] prop3 { get => buf[2]; }
public int prop4 { get => buf[3]; }
public string prop5 { get => buf[4]; }
public string prop6 { get => buf[5]; }
Now can access all prop with buf:
foreach (var item in buf) {
myList.Add(item);
}
Or direct access :
buf[1] = 10;
x = buf[1];
I have the following base, middle and derived classes below::
public class Base
{
[DataMemberAttribute()]
public int ValueBase { get; set; }
[IgnoreForAllAttribute("Param1", "Param2")]
public int IgnoreBase { get; set; }
}
public class Middle : Base
{
[DataMemberAttribute()]
public int ValueMiddle { get; set; }
[IgnoreForAllAttribute("Param1", "Param2")]
public int IgnoreMiddle { get; set; }
}
public class MostDerived : Middle
{
[DataMemberAttribute()]
public int ValueMostDerived { get; set; }
[IgnoreForAllAttribute("Param1", "Param2")]
public int IgnoreMostDerived { get; set; }
}
I need a function that given a type, I need to return DataMemberAttribute attributes for all classes in the hierarchy except for the base.
In addition, all IgnoreForAllAttribute attributes should be ignored for all classes in the graph.
var derivedObject = new MostDerived();
var attributes = MyShinyAttributeFunction(derivedObject.GetType());
// returns [] { ValueMostDerived, ValueMiddle }
Here's a LINQ sample that assumes DateMemberAttribute and IgnoreForAllAttribute are mutually exclusive
IEnumerable<PropertyInfo> MyProperties(object o)
{
o.GetType().GetProperties()
.Where(p => !(p.DeclaringType is Base))
.Where(p => p.GetCustomAttributes(false).Any(a => a is DataMemberAttribute)
}
And a sample assuming the attributes are NOT mutually exclusive
IEnumerable<PropertyInfo> MyProperties(object o)
{
o.GetType().GetProperties()
.Where(p => !(p.DeclaringType is Base))
.Where(p =>
{
var attributes = p.GetCustomAttributes(false);
return attributes.Any(a => a is DataMemberAttribute)
&& !attributes.Any(a => a is IgnoreForAllAttribute);
}
}
var properties = new List<PropertyInfo>();
GetProps(typeof(MostDerived), properties);
GetProps is a recursive function that gets the properties for the declaring type and then calls itself for the next type in the hierarchy. It stops when it gets to 'Base'
private static void GetProps(Type T, List<PropertyInfo> Properties)
{
if (T != typeof(Base))
{
var pis = T.GetProperties();
foreach (var pi in pis)
{
if (pi.DeclaringType == T &&
pi.GetCustomAttribute<DataMemberAttribute>() != null &&
pi.GetCustomAttribute<IgnoreForAllAttribute>() == null)
{
Properties.Add(pi);
}
}
GetProps(T.BaseType, Properties);
}
}
The properties list will contain properties which have the DataMemberAttribute and don't have the IgnoreForAllAttribute.
You can use the following function to get desired results:
In propertyNames, you will get the properties you need.
Usage:
List<string> propertyNames = new List<string>();
List<string> basePropertyNames = new List<string>();
MyShinyAttributeFunction(derivedObject.GetType(), ref propertyNames, ref basePropertyNames);
Function:
void MyShinyAttributeFunction(Type type, ref List<string> propertyNames, ref List<string> basePropertyNames)
{
if (type == null)
return;
MyShinyAttributeFunction(type.BaseType, ref propertyNames, ref basePropertyNames);
foreach (var property in type.GetProperties())
{
foreach (object customAttr in property.GetCustomAttributes(false))
{
if (customAttr is DataMemberAttribute)
{
if (type.BaseType.Name.Equals("Object"))
{
DataMemberAttribute attribute = (DataMemberAttribute)customAttr;
if (!basePropertyNames.Contains(property.Name))
basePropertyNames.Add(property.Name);
}
else
{
DataMemberAttribute attribute = (DataMemberAttribute)customAttr;
if (!propertyNames.Contains(property.Name) && !basePropertyNames.Contains(property.Name))
propertyNames.Add(property.Name);
}
}
}
}
}
You must make use of the following:
Type::GetProperties method, to retrieve all properties.
MemberInfo::GetCustomAttributes to retrieve the attributes for each property.
Type::BaseType property to retrieve base type for a type.
A recursive function that stops when BaseType does not exist should do the trick.
I am new to C#, I want to write a function to iterate over properties of an object and set all null strings to "". I have heard that it is possible using something called "Reflection" but I don't know how.
Thanks
public class Foo
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public int Prop3 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo();
// Use reflection to get all string properties
// that have getters and setters
var properties = from p in typeof(Foo).GetProperties()
where p.PropertyType == typeof(string) &&
p.CanRead &&
p.CanWrite
select p;
foreach (var property in properties)
{
var value = (string)property.GetValue(foo, null);
if (value == null)
{
property.SetValue(foo, string.Empty, null);
}
}
// at this stage foo should no longer have null string properties
}
}
foreach(PropertyInfo pi in myobject.GetType().GetProperties(BindingFlags.Public))
{
if (pi.GetValue(myobject)==null)
{
// do something
}
}
object myObject;
PropertyInfo[] properties = myObject.GetType().GetProperties(BindingFlags.Instance);
See http://msdn.microsoft.com/en-us/library/aa332493(VS.71).aspx