Remove the null property from object - c#

,I have one class in which I have three properties now what I want to do, if in the object if any one of null or empty then I want to remove it from the object below is my code.
public class TestClass
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
TestClass t=new TestClass();
t.Address="address";
t.ID=132;
t.Name=string.Empty;
t.DateTime=null;
Now here I want the object of TestClass but in that Name and DateTime property should not be their in the object,
is it possible?
Please help me

There's no such concept as removing a property from an individual object. The type decided which properties are present - not individual objects.
In particular, it will always be valid to have a method like this:
public void ShowDateTime(TestClass t)
{
Console.WriteLine(t.DateTme);
}
That code has no way of knowing whether you've wanted to "remove" the DateTime property from the object that t refers to. If the value is null, it will just get that value - that's fine. But you can't remove the property itself.
If you're listing the properties of an object somewhere, you should do the filtering there, instead.
EDIT: Okay, no you've given us some context:
ok I am using Schemaless database so null and empty value also store space in database that's the reason
So in the code you're using which populates that database, just don't set any fields which corresponds to properties with a null value. That's purely a database population concern - not a matter for the object itself.
(I'd also argue that you should consider how much space you'll really save by doing this. Do you really care that much?)

I was bored and got this in LINQPad
void Main()
{
TestClass t=new TestClass();
t.Address="address";
t.ID=132;
t.Name=string.Empty;
t.DateTime=null;
t.Dump();
var ret = t.FixMeUp();
((object)ret).Dump();
}
public static class ReClasser
{
public static dynamic FixMeUp<T>(this T fixMe)
{
var t = fixMe.GetType();
var returnClass = new ExpandoObject() as IDictionary<string, object>;
foreach(var pr in t.GetProperties())
{
var val = pr.GetValue(fixMe);
if(val is string && string.IsNullOrWhiteSpace(val.ToString()))
{
}
else if(val == null)
{
}
else
{
returnClass.Add(pr.Name, val);
}
}
return returnClass;
}
}
public class TestClass
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}

Hereby a 'slightly' more clear and shorter version of the accepted answer.
/// <returns>A dynamic object with only the filled properties of an object</returns>
public static object ConvertToObjectWithoutPropertiesWithNullValues<T>(this T objectToTransform)
{
var type = objectToTransform.GetType();
var returnClass = new ExpandoObject() as IDictionary<string, object>;
foreach (var propertyInfo in type.GetProperties())
{
var value = propertyInfo.GetValue(objectToTransform);
var valueIsNotAString = !(value is string && !string.IsNullOrWhiteSpace(value.ToString()));
if (valueIsNotAString && value != null)
{
returnClass.Add(propertyInfo.Name, value);
}
}
return returnClass;
}

You could take advantage of the dynamic type:
class Program
{
static void Main(string[] args)
{
List<dynamic> list = new List<dynamic>();
dynamic
t1 = new ExpandoObject(),
t2 = new ExpandoObject();
t1.Address = "address1";
t1.ID = 132;
t2.Address = "address2";
t2.ID = 133;
t2.Name = "someName";
t2.DateTime = DateTime.Now;
list.AddRange(new[] { t1, t2 });
// later in your code
list.Select((obj, index) =>
new { index, obj }).ToList().ForEach(item =>
{
Console.WriteLine("Object #{0}", item.index);
((IDictionary<string, object>)item.obj).ToList()
.ForEach(i =>
{
Console.WriteLine("Property: {0} Value: {1}",
i.Key, i.Value);
});
Console.WriteLine();
});
// or maybe generate JSON
var s = JsonSerializer.Create();
var sb=new StringBuilder();
var w=new StringWriter(sb);
var items = list.Select(item =>
{
sb.Clear();
s.Serialize(w, item);
return sb.ToString();
});
items.ToList().ForEach(json =>
{
Console.WriteLine(json);
});
}
}

May be interfaces will be handy:
public interface IAdressAndId
{
int ID { get; set; }
string Address { get; set; }
}
public interface INameAndDate
{
string Name { get; set; }
DateTime? DateTime { get; set; }
}
public class TestClass : IAdressAndId, INameAndDate
{
public string Name { get; set; }
public int ID { get; set; }
public DateTime? DateTime { get; set; }
public string Address { get; set; }
}
Creating object:
IAdressAndId t = new TestClass()
{
Address = "address",
ID = 132,
Name = string.Empty,
DateTime = null
};
Also u can put your interfaces in separate namespace and make your class declaration as internal. After that create some public factories which will create the instances of your classes.

Related

Extension method to remove not primitive property of an object

I'd like an extension method to create an object based on another but keep only the primitive properties. This object will be dumped into a log file in JSON format for logging.
Based on the classes shown below, in this sample, the created object should keep only these properties :
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
I am using .NET Framework 4.7
How can I do this?
// To use like this
var order = new Order();
var forLog = order.RemovePrimitives();
// Sample of classes
public class Order
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public List<Item> Items { get; set; }
public Address Address { get; set; }
}
public class Item{}
public class Address{}
public static class Extensions
{
public static string RemovePrimitives(this object obj)
{
// I need to create an anonymous, named 'TheNewObjectHere' object but only with primitives
// I will dump the object to push to a log file. I need only primitives
return JsonConvert.SerializeObject(TheNewObjectHere, Formatting.Indented);
}
}
Thanks
try this
public static class Extensions
{
public static string RemovePrimitives(this object obj)
{
var jsonObj = JObject.FromObject(obj);
var propToRemove = jsonObj.Properties().Where(i => !i.Value.GetType().ToString()
.Contains("JValue")).ToList();
foreach (var prop in propToRemove) prop.Remove();
return jsonObj.ToString();
}
}
You can use reflection to get primitive properties and then use JObject to build a JSON object dynamically.
public static readonly Type[] AdditionalPrimities = new[] { typeof(decimal), typeof(string) };
public static string RemovePrimitives<T>(this T obj)
{
var jObj = new JObject();
var props = GetPrimitiveProperties(obj);
foreach (var item in props)
{
var value = item.GetValue(obj);
if (value != null)
{
jObj.Add(item.Name, new JValue(value));
}
}
return jObj.ToString(Newtonsoft.Json.Formatting.Indented);
}
public static PropertyInfo[] GetPrimitiveProperties<T>()
{
var properties = typeof(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(r => r.PropertyType.IsPrimitive || (r.PropertyType.IsGenericType && Nullable.GetUnderlyingType(r.PropertyType) != null) || AdditionalPrimities.Contains(r.PropertyType))
.Select(r => r)
.ToArray();
return properties;
}
public static void Main()
{
var order = new Order { FirstName = "abc", LastName = "cde", Address = new Address(), Age2 = 3, Age = 1 };
var final = order.RemovePrimitives();
Console.WriteLine(final);
}
Fiddle

Get the values of dynamic keys from a JSON string

I have this json string and i want to get the 4th line (iValue, sValue) of every record.
My problem here is the keys vary for every record (based on the data type of the value).
Is there any way to do this on C#?
Here is an example:
{ "data": [
{
"pKey": "0",
"Entity": "tableName",
"Attribute": "CID",
"iValue": "13"
},
{
"pKey": "0",
"Entity": "tableName",
"Attribute": "username",
"sValue": "test_user1"
}] }
Here is kind of a big implementation, you will have to implement this for each iValue, fValue, etc however, it speeds up the implementation and usage. First of, here is the usage:
string rawJson = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";
var values = JsonConvert.DeserializeObject<TakeData>(rawJson).Data.Select(v => v.PureData);
Now values contains the list. Here is the usage for accessing each:
foreach (var val in values)
{
if (val is IntData i)
{
int myInt = i.iValue;
// use the rest of the properties
}
else if (val is StrData s)
{
string myStr = s.sValue;
// use the rest of the properties
}
}
And here is the implementation:
class TakeData
{
public List<TakeItAll> Data { get; set; }
}
class TakeItAll
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
private int _iValue;
public int iValue
{
get => _iValue;
set
{
_iValue = value;
PureData = new IntData { pKey = pKey, Entity = Entity, Attribute = Attribute, iValue = iValue };
}
}
private string _sValue;
public string sValue
{
get => _sValue;
set
{
_sValue = value;
PureData = new StrData { pKey = pKey, Entity = Entity, Attribute = Attribute, sValue = sValue };
}
}
public IPureData PureData { get; private set; }
}
interface IPureData
{
int pKey { get; set; }
string Entity { get; set; }
string Attribute { get; set; }
}
class IntData : IPureData
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
public int iValue { get; set; }
}
class StrData : IPureData
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
public string sValue { get; set; }
}
Of course you can use some alternatives as well. Such as using an enum in TakeItAll to keep track of the data type (or a type variable) instead of so many classes. This way However the size of the values object would be larger.
class TakeItAll
{
public int pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
private int _iValue;
public int iValue
{
get => _iValue;
set
{
_iValue = value;
ValType = typeof(string);
}
}
private string _sValue;
public string sValue
{
get => _sValue;
set
{
_sValue = value;
ValType = typeof(int);
}
}
public Type ValType { get; private set; }
}
I would deserialize this into an object supporting both types of properties and then by code try parsing either the integer or the string if the integer fails.
If the Attribute value gives you a clue as to which one to look for, you could also use that to prevent having to try parsing the integer every time.
I would not rely on the property being the "fourth" property every time, as I'm assuming this would be external data, where you may not be able to control whether these properties come out in the exact same order every time (now and in the future).
If you don't know the data type then you could use an object to handle it.
It's a good idea to deserialize JSON string to concrete class to avoid string manipulation mistake.
public class Datum
{
public object pKey { get; set; }
public string Entity { get; set; }
public string Attribute { get; set; }
public string iValue { get; set; }
public string sValue { get; set; }
}
public class DataCollection
{
public List<Datum> data { get; set; }
}
public void Test()
{
var str = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";
var list = JsonConvert.DeserializeObject<DataCollection>(str);
var keys = list.data.Select(x => x.pKey).ToList();
}
Another option is to deserialize to dynamic and inspect that:
var json = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";
var result = JsonConvert.DeserializeAnonymousType<dynamic>(json, null);
if (result.data != null)
{
for (var i = 0; i < result.data.Count; i++)
{
if (result.data[i]["iValue"] != null)
// Parse iValue
if (result.data[i]["sValue"] != null)
// Parse sValue
}
}
You could load the Json in a ExpandoObject
var expConverter = new ExpandoObjectConverter();
dynamic objList = JsonConvert.DeserializeObject<List<ExpandoObject>>(json, expConverter);
JSON array to ExpandoObject via JSON.NET
Then once you have loaded it in as a List<ExpandoObject> you may itterate over it as a dictionary.
foreach(var obj in objList)
{
//convert the object to a Dictionary and select the 4th element.
var yourresult = (obj as IDictionary<string, object>).ElementAt(3);
}
My two cents:
Get each object of the array as a KeyValuePair
var json = "your json here";
var root = JsonConvert.DeserializeObject<Root>(json);
foreach (var element in root.Data)
{
//===================================================> Here using object because your value type change. You can change it to string if your value is always wrapped in a string (like "13")
var keyValuePair = element.ToObject<Dictionary<string, object>>();
//here, for each object of the 'data' array, you can check if the desidered property exists
if (keyValuePair.ContainsKey("iValue"))
{
var propertyValue = keyValuePair["iValue"];
}
else if (keyValuePair.ContainsKey("sValue"))
{
var propertyValue = keyValuePair["sValue"];
}
// Or you can check the property name in the desidered position
if (keyValuePair.Keys.ElementAt(3) == "iValue")
{
var propertyValue = keyValuePair["iValue"];
}
else if (keyValuePair.Keys.ElementAt(3) == "sValue")
{
var propertyValue = keyValuePair["sValue"];
}
}
Where Root is
class Root
{
[JsonProperty("data")]
public List<JObject> Data { get; set; }
}
With this solution you can always know which property (iValue or sValue) is specified. On the contrary, if you use a model class which has both property names, you wouldn't know which property is specified when the value is null (unless you use additional properties/classes and a custom JsonConverter).
Edit
As Panagiotis Kanavos reminded me, the JObject class implements IDictionary<string, JToken>. So, inside your foreach you could use:
if (element["iValue"] != null)
{
var propertyValue = element["iValue"].Value<string>();
}
if (element["sValue"] != null)
{
var propertyValue = element["sValue"].Value<string>();
}
// Or you can check the property name in the desidered position
var propName = element.Properties().ElementAt(3).Name;
if (propName == "iValue")
{
var propertyValue = keyValuePair["iValue"].Value<string>();
}
else if (propName == "sValue")
{
var propertyValue = keyValuePair["sValue"].Value<string>();
}
Of course you can optimize this code and check for nulls.

moving property to anther property in class throws exception "System.InvalidCastException: 'Object must implement IConvertible.'"?

what I am trying to find away to move DynamicProperties property to JSONdata property because of that I have this reflection function to do the job when it came to DynamicProperties it throws exception "System.InvalidCastException: 'Object must implement IConvertible.'" can someone help me?
public IHttpActionResult Get(ODataQueryOptions<Client> options)
{
if(queryNew.ElementType == typeof(Client)){}
else //if (queryNew.ElementType.Name == "SelectSome`1")
{
var results = new List<Client>();
try
{
foreach (var item in queryNew)
{
var dict = ((ISelectExpandWrapper)item).ToDictionary();
var model = DictionaryToObject<Client>(dict);
results.Add(model);
}
return Ok(results);
}
catch (Exception)
{
throw;
}
}
private static T DictionaryToObject<T>(IDictionary<string, object> dict) where T : new()
{
T t = new T();
PropertyInfo[] properties = t.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (!dict.Any(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase)))
continue;
KeyValuePair<string, object> item = dict.First(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase));
Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
if(dict.Any(x => x.Key.Equals("DynamicProperties", StringComparison.InvariantCultureIgnoreCase)))
{
object temp = JsonConvert.SerializeObject(item.Value, Formatting.Indented); //Convert.ChangeType(item.Value.ToString(), newT);
t.GetType().GetProperty("JsonData").SetValue(t, temp, null);
}
object newA = Convert.ChangeType(item.Value, newT);
t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
}
return t;
}
client class
public class Client
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string ParticipantId { get; set; }
public DateTime? BirthDate { get; set; }
public int Gender { get; set; }
public byte? Age { get; set; }
public int Status { get; set; }
public string Notes { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? UpdatedDate { get; set; }
public DateTime? DeletedDate { get; set; }
public bool IsDeleted { get; set; }
public int? DefaultLanguageId { get; set; }
public Guid UserId { get; set; }
public string JsonData { get; set; }
public virtual ICollection<ClientTag> ClientTags { get; private set; }
protected IDictionary<string, object> _dynamicProperties;
public IDictionary<string, object> DynamicProperties
{
get
{
if (_dynamicProperties == null)
{
if (this.JsonData == null)
{
_dynamicProperties = new Dictionary<string, object>();
}
else
{
_dynamicProperties = Mapper.Map<IDictionary<string, object>>(JObject.Parse(this.JsonData));
}
//_dynamicProperties.Source.ListChanged += (sender, e) => { this.AssessmentData = _dynamicProperties.Source.ToString(); };
}
return _dynamicProperties;
}
}
public void UpdateJsonDataFromDynamicProperties()
{
this.JsonData = Mapper.Map<JObject>(_dynamicProperties).ToString();
}
}
When you get an IConvertable error, that means that you have tried to assign one type to another.
for example, if you try to assign textbox to string, you will get an error because you cannot assign object to string, you will have to use Iconvertible.
e.g.:
String.ToString();
Which implicitly implements Iconvertible.
I cannot tell exactly where your code fails, you didn't mention it either, I can just tell you that somewhere in the client methods, you are trying to assign two different types and you just cannot do that.
Use debug on both the server and client class and check where you are trying to assign two different types, then implement the desired Iconvertible, meaning make the needed conversion.
The only problem in your code here, is that you are trying to assign to different types.
My guess, is that this line caused trouble:
if (this.JsonData == null)
{
_dynamicProperties = new Dictionary<string, object>();
}
else
{
_dynamicProperties = Mapper.Map<IDictionary<string, object>>(JObject.Parse(this.JsonData));
}
When you are trying to assign _dynamicProperties into a dictionary object when in fact you declared _dynamicProperties as IDictionary object.
There is a subtle different between Idictionary and dictionary object, they are not of the same type. this is the change need to be done:
if (this.JsonData == null)
{
_dynamicProperties = new IDictionary<string, object>();
}
else
{
_dynamicProperties = Mapper.Map<IDictionary<string, object>>(JObject.Parse(this.JsonData));
}

Get Property Value of Nested Classes is always null

I have following two classes
public class Family
{
public string ChildName { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public Family Child { get; set; }
}
I have an instance of Employee class as follows.
Employee employee = new Employee();
employee.Name = "Ram";
employee.Id = 77;
employee.Child = new Family() { ChildName = "Lava" };
I have a method which gets the property value based on the property name as follows:
public static object GetPropertyValue(object src, string propName)
{
string[] nameParts = propName.Split('.');
if (nameParts.Length == 1)
{
return src.GetType().GetRuntimeProperty(propName).GetValue(src, null);
}
foreach (String part in nameParts)
{
if (src == null) { return null; }
Type type = src.GetType();
PropertyInfo info = type.GetRuntimeProperty(part);
if (info == null)
{ return null; }
src = info.GetValue(src, null);
}
return src;
}
In the above method,when I try to get property value of nested class like
GetPropertyValue(employee, "employee.Child.ChildName")
or
GetPropertyValue(GetPropertyValue(employee, "Family"), "ChildName"
doesn't return any value because type.GetRuntimeProperty(part) is always null.
Is there any way to fix this problem?
You problem lies in this line:
foreach (String part in nameParts)
Because you are iterating over each part of nameParts, you are also iterating over "employee", which of course is not a valid property.
Try either this:
foreach (String part in nameParts.Skip(1))
Or calling the method like this:
GetPropertyValue(employee, "Child.ChildName")
(Notice no "employee.", because you already pass in an employee)
The problem in this case is that when you split the string employee.Child.ChildName, the "employee" is the first part. However, employee is not a property of the source i.e. Employee Class.
Try this:
public class Program
{
public static void Main()
{
Employee employee = new Employee();
employee.Name = "Ram";
employee.Id = 77;
employee.Child = new Family() { ChildName = "Lava" };
GetPropertyValue(employee, "employee.Child.ChildName");
}
public class Family
{
public string ChildName { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public Family Child { get; set; }
}
public static object GetPropertyValue(object src, string propName)
{
string[] nameParts = propName.Split('.');
if (nameParts.Length == 1)
{
return src.GetType().GetRuntimeProperty(propName).GetValue(src, null);
}
nameParts = nameParts.Skip(1).ToArray();
foreach (String part in nameParts)
{
if (src == null) { return null; }
Type type = src.GetType();
PropertyInfo info = type.GetRuntimeProperty(part);
if (info == null)
{ return null; }
src = info.GetValue(src, null);
}
return src;
}
Here, i have skipped the first part of the string i.e. "employee". However, you can solve the problem by passing Child.ChildName
This question is around 2 years old, but I found a another working solution for you question, which is easy to understand. If you initialize the object in calling calss constructor you can use dot(.) notation to assign or read property. Example -
public class Family{
public string ChildName { get; set; }
}
public class Employee{
public int Id { get; set; }
public string Name { get; set; }
public Family Child { get; set; }
public Employee(){
Child = new Family();
}
}
Employee emp = new Employee();
emp.Family.ChildName = "Nested calss attribute value";

Comparing Object properties using reflection

I have two classes Address and Employee as follows:
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class Employee
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public Address EmployeeAddress { get; set; }
}
I have two employee instances as follows:
var emp1Address = new Address();
emp1Address.AddressLine1 = "Microsoft Corporation";
emp1Address.AddressLine2 = "One Microsoft Way";
emp1Address.City = "Redmond";
emp1Address.State = "WA";
emp1Address.Zip = "98052-6399";
var emp1 = new Employee();
emp1.FirstName = "Bill";
emp1.LastName = "Gates";
emp1.EmployeeAddress = emp1Address;
var emp2Address = new Address();
emp2Address.AddressLine1 = "Gates Foundation";
emp2Address.AddressLine2 = "One Microsoft Way";
emp2Address.City = "Redmond";
emp2Address.State = "WA";
emp2Address.Zip = "98052-6399";
var emp2 = new Employee();
emp2.FirstName = "Melinda";
emp2.LastName = "Gates";
emp2.EmployeeAddress = emp2Address;
Now how can I write a method which compares these two employees and returns the list of properties which have different values. So in this example I would like the result to be FirstName and Address.AddressLine1 .
Like LBushskin said, you do not have to do this. This is not the fastest way! Buy if you want, try this:
public static List<PropertyInfo> GetDifferences(Employee test1, Employee test2)
{
List<PropertyInfo> differences = new List<PropertyInfo>();
foreach (PropertyInfo property in test1.GetType().GetProperties())
{
object value1 = property.GetValue(test1, null);
object value2 = property.GetValue(test2, null);
if (!value1.Equals(value2))
{
differences.Add(property);
}
}
return differences;
}
You don't necessarily need reflection to perform the comparison. You can write a comparer class that takes two instances of Employee or Address, and compares each field that should match. For any that don't match, you can add a string (or PropertyInfo) element to some list to return to the caller.
Whether you return a PropertyInfo, MemberInfo, or just a string depends on what the caller needs to do with the result. If you actually need to visit the fields that contain differences, the PropertyInfo/MemberInfo may be better - but to just report the differences a string is probaby sufficient.
The main value of reflection would be to write a general purpose object comparer that could take two instances of any kind of object and compare their public fields and properties. This helps avoid writing repetetive comparison code over and over - but that doesn't seem like the case you're in.
Here is a generic and recursive solution based on Oskar Kjellin's awnser.
I have posted this code as gist as well, so you can check the latest version or star/clone/fork it :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
protected List<KeyValuePair<Type, PropertyInfo>> RecrusiveReflectionCompare<T>(T first, T second)
where T : class
{
var differences = new List<KeyValuePair<Type, PropertyInfo>>();
var parentType = first.GetType();
void CompareObject(object obj1, object obj2, PropertyInfo info)
{
if (!obj1.Equals(obj2))
{
differences.Add(new KeyValuePair<Type, PropertyInfo>(parentType, info));
}
}
foreach (PropertyInfo property in parentType.GetProperties())
{
object value1 = property.GetValue(first, null);
object value2 = property.GetValue(second, null);
if (property.PropertyType == typeof(string))
{
if (string.IsNullOrEmpty(value1 as string) != string.IsNullOrEmpty(value2 as string))
{
CompareObject(value1, value2, property);
}
}
else if (property.PropertyType.IsPrimitive)
{
CompareObject(value1, value2, property);
}
else
{
if (value1 == null && value2 == null)
{
continue;
}
differences.Concat(RecrusiveReflectionCompare(value1, value2));
}
}
return differences;
}
public IEnumerable<PropertyInfo> GetNotEqualsProperties(Employee emp1, Employee emp2)
{
Type employeeType = typeof (Employee);
var properies = employeeType.GetProperties();
foreach (var property in properies)
if(!property.GetValue(emp1, null).Equals(property.GetValue(emp2, null))) //TODO: check for null
yield return property;
}
And for complex properties you have to override Equals method
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public override bool Equals(object obj)
{
if (obj as Address == null)
return false;
return ((Address) obj).AddressLine1.Equals(AddressLine1);
}
}
No need for reflection. Of course, this example is returning a string with the property names...if you need the actual PropertyInfo object, things would get a little more difficult, but not by much.
public static IEnumerable<string> DiffEmployees
(Employee one, Employee two)
{
if(one.FirstName != two.FirstName)
yield return "FirstName";
if(one.LastName != two.LastName)
yield return "LastName";
if(one.Address.AddressLine1 != two.Address.AddressLine1)
yield return "Address.AddressLine1";
// And so on.
}

Categories

Resources