c# reflection comparing 2 objects with boolean properties - c#

I have two objects with several properties that are of type boolean.
The properties are identical in terms of naming and I just want to make sure they are equal. I do a lot of these checks and want to know if anyone has any suggestion of a method that can do the following code in one step but is dynamic enough to check the property options by name if they have the same name?
if (options != null && other != null)
return options.Quantities == other.Quantities &&
options.SKUEntityKey == other.SKUEntityKey &&
options.LineItemType_Type == other.LineItemType_Type &&
options.SKUIdentifier == other.SKUIdentifier &&
options.Identifier == other.Identifier;
If what I'm asking isn't clear please let me know

class Program
{
static void Main(string[] args)
{
ReflectOverProperties<TestClass, TestClass2>(new TestClass(), new TestClass2());
Console.ReadLine();
}
public static void ReflectOverProperties<T, Z>(T x, Z y)
{
var properties = typeof(T).GetProperties();
foreach (var item in properties)
{
CompareProperty(x, y, item.Name);
}
}
private static void CompareProperty<T, Z>(T x, Z y, string itemName)
{
dynamic originalValue = GetPropValue(x, itemName);
dynamic newValue = GetPropValue(y, itemName);
PropertyCompare(itemName, originalValue, newValue);
}
private static void PropertyCompare(string itemName, dynamic originalValue, dynamic newValue)
{
if (originalValue != newValue)
{
Console.Write($"Property {itemName} does not match");
}
}
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
}
public class TestClass
{
public TestClass()
{
Test1 = false;
Test2 = false;
Test3 = false;
}
public bool Test1 { get; set; }
public bool Test2 { get; set; }
public bool Test3 { get; set; }
}
public class TestClass2
{
public TestClass2()
{
Test1 = false;
Test2 = false;
Test3 = true;
}
public bool Test1 { get; set; }
public bool Test2 { get; set; }
public bool Test3 { get; set; }
}
Here is some Code I modified pretty quick, which runs in console app. Hopefully set you in the right direction, was doing the same object now can be different. Just using some basic reflection and dynamic properties.

I hope this terrible console app will at least give an idea of how to go about doing what you want:
static void Main(string[] args)
{
Person steve = new Person()
{
IsHungry = true,
IsLazy = false,
IsSleepy = true
};
Dog bella= new Dog()
{
IsHungry = true,
IsLazy = false,
IsSleepy = true
};
bool match = DoAllBoolPropertiesMatch(steve, bella);
Console.WriteLine($"\r\n----> Do Bools in Objects Match?: {match}");
}
private static bool DoAllBoolPropertiesMatch(object obj1, object obj2)
{
// For each Boolean property of object 1, check object 2:
foreach(PropertyInfo propInfo in obj1.GetType().GetProperties())
{
// Property is boolean.
if(propInfo.PropertyType == typeof(Boolean))
{
// Look for a property on obj2 with the same name that also returns a bool.
PropertyInfo matchingPropInfo = obj2.GetType().GetProperty(propInfo.Name, typeof(Boolean));
if(matchingPropInfo != null)
{
Console.WriteLine($"Evaluating Property {propInfo.Name} from obj1:");
Console.WriteLine($" - Value for Obj1 = [{propInfo.GetValue(obj1)}]");
Console.WriteLine($" - Value for Obj2 = [{matchingPropInfo.GetValue(obj2)}]");
if(Convert.ToBoolean(propInfo.GetValue(obj1)) != Convert.ToBoolean(matchingPropInfo.GetValue(obj2)))
return false;
}
}
}
return true;
}
public class Person
{
public bool IsHungry { get; set; }
public bool IsSleepy { get; set; }
public bool IsLazy { get; set; }
}
public class Dog
{
public bool IsHungry { get; set; }
public bool IsSleepy { get; set; }
public bool IsLazy { get; set; }
}

Related

Check parameter range on generic types

Is there a way to do something like "string.Compare()", but for generic types. I want to check the range of some property values.
Here is what I am doing as a work around, but it is pretty ugly:
public class SomeClass<T>
{
public T MinValue { get; set; }
public T MaxValue { get; set; }
private T _value;
public T Value
{
get { return _value; }
set
{
_value = value;
// Restrict range to Min/Max
if (Comparer<T>.Default.Compare(MaxValue, value) < 0)
_value = MaxValue;
if (Comparer<T>.Default.Compare(MinValue, value) > 0)
_value = MinValue;
}
}
}
This code demonstates what I was talking about in my comment. Of course you will have to modify it to fit with your precise paradigm, of using it in a comparer, but this should be clear enough...
public class Program
{
public static void Main(string[] args)
{
System.Console.WriteLine("Hello World!");
TestObject testObject = new TestObject(15);
TestObject testObject2 = new TestObject(9);
TestObject testObject3 = new TestObject(31);
System.Console.ReadLine();
}
}
public class TestObject
{
[ValidateIntMin(Min = 10)]
[ValidateIntMax(30)]
public int SomeInt { get; set; }
public TestObject(int value)
{
SomeInt = value;
if (!Validator.Validate(this))
{
System.Console.WriteLine("Invalid Value assigned: " + value);
}
else
{
System.Console.WriteLine("" + SomeInt + " was a valid value");
}
}
}
public class ValidateIntMax : Attribute
{
public int Max { get; set; }
public ValidateIntMax(int MaxValue)
{
Max = MaxValue;
}
}
public class ValidateIntMin: Attribute
{
public int Min { get; set; }
}
public static class Validator
{
public static bool Validate<T>(T input) {
var attrType = typeof(T);
var properties = attrType.GetProperties();
bool isValid = true;
foreach (PropertyInfo propertyInfo in properties)
{
var customerMaxValueInt = propertyInfo.GetCustomAttributes(typeof(ValidateIntMax), false).FirstOrDefault();
var customerMinValueInt = propertyInfo.GetCustomAttributes(typeof(ValidateIntMin), false).FirstOrDefault();
if (customerMaxValueInt != null)
{
if (propertyInfo.PropertyType == typeof(int))
{
var currentPropertyInfoBeingTested = (int)propertyInfo.GetValue(input);
var currentMaxValueToVerifyAgainst = ((ValidateIntMax)customerMaxValueInt).Max;
if (currentPropertyInfoBeingTested > currentMaxValueToVerifyAgainst)
{
isValid = false;
}
}
}
if (customerMinValueInt != null)
{
if (propertyInfo.PropertyType == typeof(int))
{
var currentPropertyInfoBeingTested = (int)propertyInfo.GetValue(input);
var currentMaxValueToVerifyAgainst = ((ValidateIntMin)customerMinValueInt).Min;
if (currentPropertyInfoBeingTested < currentMaxValueToVerifyAgainst)
{
isValid = false;
}
}
}
}
return isValid;
}
}
Should give the output:
Hello World!
15 was a valid value
Invalid Value assigned: 9
Invalid Value assigned: 31
Of course you can add validation for different types, etc.
This is just to show a totally custom way of setting up your attributes.
I recommend you read up on the ValidationAttribute however, to see if you can't use the implemented functionality.
But this is just a PoC piece.

C# how to set parameter value by Func Delegate

I need a clean way to update an object using parameters of same class.
I am defining list of fields as Func<T, object> delegates. These are lists that should be compared and updated if nessecary. Unfortunately I can't figure out a clean way to implement it.
Following code doesn't work:
public class UpdatableClass
{
public int Id { get; set; }
public int IntValue { get; set; }
public string StringValue { get; set; }
public DateTime ModifiedDate { get; set; }
private List<Func<UpdatableClass, object>> UpdatableFields =
new List<Func<UpdatableClass, object>>()
{
c => c.IntValue,
c => c.StringValue
};
public bool Update(UpdatableClass newValues)
{
bool isUpdated = false;
foreach (var fieldSelector in UpdatableFields)
{
object oldValue = fieldSelector(this);
object newValue = fieldSelector(newValues);
if (!newValue.Equals(oldValue))
{
oldValue = newValue;
isUpdated = true;
}
}
return isUpdated;
}
}
[TestFixture]
public class UpdatableClassTests
{
[Test]
public void TestUpdateMethod()
{
UpdatableClass oldObject = new UpdatableClass()
{
StringValue = "OldString",
IntValue = 3,
};
bool isUpdated = oldObject.Update(new UpdatableClass() { StringValue = "NewString", IntValue = 4 });
Assert.IsTrue(isUpdated);
Assert.AreEqual("NewString", oldObject.StringValue);
Assert.AreEqual(4, oldObject.IntValue);
}
}
This code can be used as possible solution for the problem. Instead of get only Func<T, object> you can use a tuple for both getter and setter (Func<UpdatableClass, object> Get, Action<UpdatableClass, object> Set). I don't think that it's the best solution, but it resolves question and make test passing
public class UpdatableClass
{
public int Id { get; set; }
public int IntValue { get; set; }
public string StringValue { get; set; }
public DateTime ModifiedDate { get; set; }
private List<(Func<UpdatableClass, object> Get, Action<UpdatableClass, object> Set)> UpdatableFields =
new List<(Func<UpdatableClass, object>, Action<UpdatableClass, object>)>
{
(c => c.IntValue, (c, v) => { c.IntValue = Convert.ToInt32(v); }),
(c => c.StringValue, (c, v) => { c.StringValue = v.ToString(); })
};
public bool Update(UpdatableClass newValues)
{
bool isUpdated = false;
foreach (var field in UpdatableFields)
{
object oldValue = field.Get(this);
object newValue = field.Get(newValues);
if (!newValue.Equals(oldValue))
{
field.Set(this, newValue);
isUpdated = true;
}
}
return isUpdated;
}
}

How do you migrate from a list to a class C# DataContract Serialization?

How can I migrate a configuration to a new class from a list of bools? Previously it used a list of bool, but the list was being abused as a class, with each index having a specific meaning like a field.
I want to migrate it from a List, to a class that instead acts as the list for serialization purposes, but exposes normal fields to the rest of the application.
How can I write class ListEmulator so that it serializes out to a list, without introducing new xml tags?
old code
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new List<bool>();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public List<bool> AList { get; set; }
}
}
new code.
namespace
{
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AListEmulator = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember]
public ListEmulator AListEmulator { get; set; }
}
}
public class ListEmulator
{
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
}
The reason a list is needed, is there is old migration code that needs to be ported for when there was only 1 element, then 2, 3, 4 with different defaults for each. If it weren't for the fact that I have existing deployed configuration files in the original format, it would probably be time for them to all be named in the XML individually. However, I need to retain the current format for now. For the sake of migration I'm wondering how I can accomplish the above.
One option would be for your ListEmulator to inherit from Collection<bool>, and then add specific named properties to access elements in the array, like so:
public class ListEmulator : Collection<bool>
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
void AddAllDefaults()
{
// Customize the code here to upgrade old collections with fewer than 4 elements to the current 4-element format.
if (Count < 1)
Add(IsPlannedDefault);
if (Count < 2)
Add(IsCompletedDefault);
if (Count < 3)
Add(IsRemainingDefault);
if (Count < 4)
Add(IsSerialDefault);
}
public ListEmulator() { }
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get { return this.ElementAtOrDefault(0, IsPlannedDefault); } set { AddAllDefaults(); this[0] = value; } }
public bool IsCompleted { get { return this.ElementAtOrDefault(1, IsCompletedDefault); } set { AddAllDefaults(); this[1] = value; } }
public bool IsRemaining { get { return this.ElementAtOrDefault(2, IsRemainingDefault); } set { AddAllDefaults(); this[2] = value; } }
public bool IsSerial { get { return this.ElementAtOrDefault(3, IsSerialDefault); } set { AddAllDefaults(); this[3] = value; } }
protected override void InsertItem(int index, bool item)
{
if (index > 3)
throw new ArgumentOutOfRangeException("index > 3");
base.InsertItem(index, item);
}
}
Then in your Configuration simply replace List<bool> with ListEmulator, keeping the old element name:
[DataMember]
public ListEmulator AList { get; set; }
Because this type implements IEnumerable<T>, the DataContractSerializer will serialize it as a collection rather than as an object with properties. (You might want to change the class name since it's really not a list emulator at this point.) However, this only works if you do not add any initial values to the collection from within the default constructor.
Another option would be to add a surrogate property to Configuration that handles the necessary conversions, and mark the ListEmulator AList as not serialized:
[DataContract]
public class Configuration
{
public const string FileName = "Configuration.xml";
public Configuration()
{
AList = new ListEmulator();
AGuidList = new List<Guid>();
}
[DataMember]
public List<Guid> AGuidList { get; set; }
[DataMember(Name = "AList")]
bool[] AlistArray
{
get
{
return AList == null ? null : AList.ToArray();
}
set
{
AList = new ListEmulator(value);
}
}
[IgnoreDataMember] // Do not serialize this property directly
public ListEmulator AList { get; set; }
}
public class ListEmulator
{
const bool IsPlannedDefault = false; // Change to the appropriate values.
const bool IsCompletedDefault = false;
const bool IsRemainingDefault = false;
const bool IsSerialDefault = false;
public ListEmulator(IList<bool> list)
{
IsPlanned = list.ElementAtOrDefault(0, IsPlannedDefault);
IsCompleted = list.ElementAtOrDefault(1, IsCompletedDefault);
IsRemaining = list.ElementAtOrDefault(2, IsRemainingDefault);
IsSerial = list.ElementAtOrDefault(3, IsSerialDefault);
}
public ListEmulator()
{
new ListEmulator(true, true, true, true);
}
public ListEmulator(bool item0, bool item1, bool item2, bool item3)
{
this.IsPlanned = item0;
this.IsCompleted = item1;
this.IsRemaining = item2;
this.IsSerial = item3;
}
public bool IsPlanned { get; set; }
public bool IsCompleted { get; set; }
public bool IsRemaining { get; set; }
public bool IsSerial { get; set; }
public bool[] ToArray()
{
return new[] { IsPlanned, IsCompleted, IsRemaining, IsSerial };
}
}
Both options use the following extension method:
public static class ListExtensions
{
public static T ElementAtOrDefault<T>(this IList<T> list, int index, T defaultValue)
{
if (index < 0)
throw new ArgumentOutOfRangeException(string.Format("index = {0}", index));
if (list == null || index >= list.Count)
return defaultValue;
return list[index];
}
}

C# Accessing custom attribute of owner object

How can I access the custom attribute of the parent or owner object.
Look at the FieldInfo property of the SQLFieldInfo struct
Here's a more detailed program that will compile and run that shows what I need.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Employee myclass = new Employee();
// Load from sql server...
myclass.Name = "Alain";
myclass.Age = 51;
//----
MessageBox.Show(myclass.Name.ToString()); // Should return Alain
MessageBox.Show(myclass.Age.FieldInfo.Type.ToString()); // Should output "int"
}
}
// This next class is generated by a helper exe that reads SQL table design and create the class from it
[SQLTableAttribute(DatabaseName = "Employees", Schema = "dbo", TableName = "Employees")]
public class Employee
{
[SQLFieldAttribute(FieldName = "ID", Type = SqlDbType.Int)]
public SQLFieldInfo<int> ID { get; set; }
[SQLFieldAttribute(FieldName = "Name", Type = SqlDbType.NVarChar, Size = 200)]
public SQLFieldInfo<String> Name { get; set; }
[SQLFieldAttribute(FieldName = "Age", Type = SqlDbType.Int)]
public SQLFieldInfo<int> Age { get; set; }
}
public struct SQLFieldInfo<T>
{
private readonly T value;
public SQLFieldInfo(T Value)
{
this.value = Value;
}
public static implicit operator SQLFieldInfo<T>(T Value)
{
return new SQLFieldInfo<T>(Value);
}
public T Value
{
get
{
return this.value;
}
}
public override string ToString()
{
return this.value.ToString();
}
public SQLFieldAttribute FieldInfo
{
get
{
// Need to retreive the attribute class of the parent or declaring member
return null;
}
}
}
// Holds the sql field information
public class SQLFieldAttribute : Attribute
{
public string FieldName { get; set; }
public SqlDbType Type { get; set; }
public bool AllowNull { get; set; }
public int Size { get; set; }
}
// Holds the sql table information
public class SQLTableAttribute : Attribute
{
public string DatabaseName { get; set; }
public string Schema { get; set; } = "dbo";
public string TableName { get; set; }
}
Thank you!
Alain
My data class is as follows (should be fairly translatable to A above):
public class Foo
{
[Argument(Help = "Name", AssignmentDelimiter = "=")]
public string Name
{
get;
set;
}
}
A helper class is responsible of reading attribute values of objects:
static public string GetCommandLineDelimiter<T>(Expression<Func<T>> property)
{
if(property != null)
{
var memberExpression = (MemberExpression)property.Body;
string propertyName = memberExpression.Member.Name;
PropertyInfo prop = typeof(Arguments).GetProperty(propertyName);
if(prop != null)
{
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(ArgumentAttribute), true);
if(dbFieldAtts.Length > 0)
{
return ((ArgumentAttribute)dbFieldAtts[0]).AssignmentDelimiter;
}
}
}
return null;
}
To use it, simply:
string delimiter = GetCommandLineDelimiter(() => myObject.Name);
That will get the attribute value of AssignmentDelimiter on property Name, i.e. "=".
First, MSDN is your friend.
Then, if you want to get the attributes for ancestors just specify true in the inherit flag of the method:
var attribute = typeof(A).GetProperty("myprop").GetCustomAttributes(true)
.OfType<MycustomAttrib>().FirstOrDefault();
This works. I am doing a lazy initialization of a reference to the custom attribute by using reflection to look at all the properties of all the types.
public class MycustomAttribAttribute : Attribute
{
public MycustomAttribAttribute(string name)
{
this.Name=name;
}
public string Name { get; private set; }
}
class A
{
public A() { MyProp=new B(); }
[MycustomAttrib(name: "OK")]
public B MyProp { get; set; }
}
class B
{
private static Lazy<MycustomAttribAttribute> att = new Lazy<MycustomAttribAttribute>(() =>
{
var types = System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes;
foreach(var item in types)
{
foreach(var prop in item.DeclaredProperties)
{
var attr = prop.GetCustomAttributes(typeof(MycustomAttribAttribute), false);
if(attr.Length>0)
{
return attr[0] as MycustomAttribAttribute;
}
}
}
return null;
});
public string MyProp2
{
get
{
return att.Value.Name;
}
}
}
class Program
{
static void Main(string[] args)
{
// Finds the attribute reference and returns "OK"
string name = (new A()).MyProp.MyProp2;
// Uses the stored attribute reference to return "OK"
string name2 = (new A()).MyProp.MyProp2;
}
}

Is it possible to set the property of the condition dynamically?

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

Categories