Recently, I ran into a problem of comparing 2 objects of the same class in C#. I need to know which fields/properties are changed.
Here is the example:
SampleClass
{
string sampleField1;
int sampleField2;
CustomClass sampleField3;
}
And I have 2 SampleClass object, object1 and object2, for example.
These 2 objects have some different field value.
Can anyone know the best approach to get which fields are different?
And how to get the (string) names of that different fields/properties?
I heard of Reflection in .Net. Is that the best approach in this situation?
And if we didn't have the CustomClass field? (I just make this field for a more general approach, that field does not exist in my case)
If you want Generic way to get all changed properties
you can use this method (and it is using reflection ^_^ )
public List<string> GetChangedProperties(object obj1, object obj2)
{
List<string> result = new List<string>();
if(obj1 == null || obj2 == null )
// just return empty result
return result;
if (obj1.GetType() != obj2.GetType())
throw new InvalidOperationException("Two objects should be from the same type");
Type objectType = obj1.GetType();
// check if the objects are primitive types
if (objectType.IsPrimitive || objectType == typeof(Decimal) || objectType == typeof(String) )
{
// here we shouldn't get properties because its just primitive :)
if (!object.Equals(obj1, obj2))
result.Add("Value");
return result;
}
var properties = objectType.GetProperties();
foreach (var property in properties)
{
if (!object.Equals(property.GetValue(obj1), property.GetValue(obj2)))
{
result.Add(property.Name);
}
}
return result;
}
Please note that this method only gets Primitive type properties that have changed and reference type properties that refer to the same instance
EDIT: Added validation in case if obj1 or obj2 is primitive type (int,string ... ) because I tried to pass string object and it will give an error
also fixed bug of checking whether the two values are equal
A slight modification of another answer posted here, but this one works with properties that are not string types, doesn't use an internal list and does automatic some preliminary type checking as it's generic:
public IEnumerable<string> ChangedFields<T>(T first, T second)
{
if (obj1.GetType() != obj2.GetType())
throw new ArgumentOutOfRangeException("Objects should be of the same type");
var properties = first
.GetType()
.GetProperties();
foreach (var property in properties)
{
if(!object.Equals(property.GetValue(first), property.GetValue(second)))
{
yield return property.Name;
}
}
}
If you need to compare two objects as part of your business logic reflection is the way to go, unless of course you can write comparator classes for each type.
If you want to compare two objects at run time during debugging, there is a neat plugin called Oz Code that can do that for you, something like this:
Related
I have a List<object> which is a collection of various type of objects.
I am writing a helper method which will return a specific type of object. The helper method will accept type name as string parameter.
Note: I am using 3.5 framework.
If you need to use a string as parameter you can't rely on OfType<T>() extension method. Fortunately it's easy to emulate:
public IEnumerable<object> OfType(this List<object> list, string typeName)
{
return list.Where(x => x != null && x.GetType().Name == typeName);
}
As pointed out by #ChrisSinclair in the comment this solution does not manage conversions, casts and inheritance/interfaces. Casts (because of user defined conversion operators) and conversions (because of TypeConverters and the IConvertible interface) are little bit more tricky. For simple (implicit) casts (like with inheritance and interfaces) you can use this:
public IEnumerable<object> OfType(this List<object> list, string typeName)
{
Type type = Type.GetType(typeName);
return list.Where(x => x != null && type.IsAssignableFrom(x.GetType()));
}
How to perform conversions (even with CUSTOM CONVERSION OPERATORS) at run-time
I found I needed something like the code I posted in this answer but I had to extend it a little bit, here a better implementation that takes care of custom casts and conversions.
Put everything inside a CastExtensions class (or update code if you don't) then declare this small enum for its options:
[Flags]
public enum CastOptions
{
None = 0,
ExcludeNulls = 1,
UseConversions = 2
}
The problem is that C# in general is a statically typed language, it means that almost everything (about types) must be known at compile time (then to perform a cast you have to know type your want to cast to at compile time). This function handles simple cases (like derivation) and more complex ones (interfaces, custom conversion operators - casts - and conversions - when required).
public static IEnumerable<object> OfType(this List<object> list,
string typeName, CastOptions options)
{
Type type = Type.GetType(typeName);
foreach (var obj in list)
{
if (Object.ReferenceEquals(obj, null))
{
if (options.HasFlag(CastOptions.ExcludeNulls))
continue;
yield return obj;
}
var objectType = obj.GetType();
// Derived type?
if (type.IsAssignableFrom(objectType))
yield return obj;
// Should we try to convert?
if (!options.HasFlag(CastOptions.UseConversions))
continue;
// Castable?
object convertedValue = null;
try
{
var method = typeof(CastExtensions)
.GetMethod("Cast", BindingFlags.Static|BindingFlags.NonPublic)
.MakeGenericMethod(type);
convertedValue = method.Invoke(null, new object[] { obj });
}
catch (InvalidCastException)
{
// No implicit/explicit conversion operators
}
if (convertedValue != null)
yield return convertedValue;
// Convertible?
if (options.HasFlag(CastOptions.UseConversions))
{
try
{
IConvertible convertible = obj as IConvertible;
if (convertible != null)
convertible.ToType(type, CultureInfo.CurrentCulture);
}
catch (Exception)
{
// Exact exception depends on the source object type
}
}
}
}
Note that conversion may be or not equivalent to a cast, actually it depends on
the implementation and the exact types involved in the operation (that's why you
can enable or disable this feature through options).
This is a small helper function needed for cast at run-time:
private static T Cast<T>(object obj)
{
return (T)obj;
}
We may emit this code at run-time (I suppose even using expressions but I didn't try) but a small helper method will generate exactly the code we need (conversion from an object to a generic known at run-time type). Note that this cast function doesn't work as expected for value types, for example:
int a = 1;
float a = Cast<float>(a); // Run-time error
This is because (object)1 cannot be converted to anything else than int (this is true for all boxed value types). If you're using C# 4.0 you should change object for parameter obj to dynamic and everything will work as expected (for all types).
Maybe something like that :
var ofTypeTypeA = myList.OfType<TypeA>();
A clean way is to force the user to specify the type as type to avoid loose strings in your application.
Then you could use generics and just use the type you are interested in. That would also allow the caller to skip the cast when using the IEnumerable later.
So instead of this:
List<object> newList = GetOfType(myList, "SomeObject");
// CAST!!
SomeObject someObject = newList[0] as SomeObject;
if (someObject != null)
// use object
you would just do:
IEnumerable<SomeObject> newList = myList.OfType<SomeObject>();
foreach (SomeObject someObject in newList){
// no cast neccessary
This makes it unsensitive in the future if you should rename the class SomeObject (because refactoring tools would pick up on the class name instead of the string)
You can use Enumerable.OfType
var input = new List<object>();
input.Add(1);
input.Add("foo");
var bar = input.OfType<string>();
I guess you need to cast a single object extracted from the list to a strongly-typed object. And not to cast all the list to it. Otherwise use List<MyType>.
So I would go with this: How to cast to a type in C#.
You could use the is operator (or pass the type and check for that also using is). Here is an example of using the is operator:
foreach (var ctl in ControlsList)
{
if (ctl is CheckBox)
//Do this
else if (ctl is TextBox)
//DoThis
}
And by passing the type as string in the parameter, you could do something similar to get the type to test against:
Type t = System.Type.GetType("System.Int32");
I think I'm having boxing issues
foreach(var p in item.GetType().GetProperties().
Where(p => p.GetValue(original, null) is ValueType))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (!originalValue.Equals(modifiedValue))
kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
originalValue is never equal to modifiedValue, Im guessing it's because they are boxed inside Object. But how do I fix it?
It is not a boxing issue. Equals is a virtual method, which the boxed value types override just fine.
However, I am not sure what the issue is. Could it be that there aren’t actually any matching properties? Remember that GetProperties() without any parameters will only return public properties. If the properties you need are private, you need to add some BindingFlags:
GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
(I’m assuming here that you don’t want static properties.)
Are you also sure that it is actually properties that you are after and not fields? Remember that if you declare something as
public string Name;
then it’s a field, whereas
public string Name { get; set; }
is a property. If it’s actually fields you need, you need to use GetFields() instead of GetProperties() with the same binding flags.
Linq is a great tool, but I'm not sure why you're using it here. You're actually causing the set of properties to get iterated twice, which is very expensive. I'd write the code without Linq. Also, there's no need to get the value more than once, which is again very expensive. Give this code a try. It avoids the flaws I pointed out and was comparing correctly when I made and tested a dummy class with it:
foreach(PropertyInfo p in item.GetType().GetProperties())
{
if (p.PropertyType.BaseType == typeof(ValueType) || p.PropertyType == typeof(string))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (originalValue != modifiedValue) kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
}
Also, note that strings are not a ValueType although they do implement a value comparison.
From MSDN: Object.Equals :
The default implementation of Equals supports reference equality for
reference types, and bitwise equality for value types. Reference
equality means the object references that are compared refer to the
same object. Bitwise equality means the objects that are compared have
the same binary representation.
That means that in your case this 2 objects (if they are reference types) are never point to the same instance.
There is no an easy way to resolve this in so generic way as you would like to do.
But you can implement (just an example) an IComparable on those types you gonna to compare, and after in this iteration check if the type of the value rturned implements that interface, so cast and call it's implemented IComparable.CompareTo method.
You can check if the object implements specified interfacce, in this current case IComparable, you can do something like this:
originalValue .GetType().GetInterfaces().Any(x =>
x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IComparable))
Hope this helps.
I have a series of methods to write, but I think there is some commonality (well, I know there is). The method I'd like to see will take two things, an object and... well, I'm not so sure about the second one, but probably a string.
The object should be generic, although it can only be from a set list (in this case, that commonality seems to be that they inherit from both INotifyPropertyChanging and INotifyPropertyChanged interfaces).
The string should be the name of a property within the generic object. It should be checked to see if that property exists within that object before being put into use (it would be used as a way to compare the objects by that given property).
So I guess the process would be... generic object gets passed into method (along with property name string). A check to see if the object contains the property. If it does, continue and somehow have access to 'object.PropertyName' where 'PropertyName' was the supplied string.
I don't know if it's easy or possible or even wise, but I know that it would save me some time.
Thanks in advance for any advice you might be able to offer with this.
Edit: Thanks for the all the replies so far guys. Let me clarify some things:
Clarification of 'access'
When I said, "... and somehow have access to 'object.PropertyName'", what I meant was that the method should be able to use that property name as if it were just a property of that object. So, let's say the string passed in was "ClientName", there would be the ability to read (possibly write, although at the moment I don't think so as it's just a check) object.ClientName, if it was determined that existed.
What I'm trying to do
I have a WCF service which accesses an SQL database using Linq. The objects I spoke of are entities, generated from the program SQLMetal.exe, so my objects are things like 'Client', 'User' and this sort of thing. I wrote a method which took a List of entities. This method added only those entities which did not exist within the collection (some could have been duplicates). It figured out which ones were duplicates by checking a property within the entity (which corresponds to data in a column of the database). It's that property which I figured might be variable.
It sounds like you don't really want to check if it's a certain type, and if that is so then you don't have to and its actually easier not to check the type. This shows how to check if the property exists and if it is readable and writeable and shows how to use it after it's found:
private void Form1_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
PropertyInfo info = GetProperty(sb, "Capacity");
//To get the value of the property, call GetValue on the PropertyInfo with the object and null parameters:
info.GetValue(sb, null);
//To set the value of the property, call SetValue on the PropertyInfo with the object, value, and null parameters:
info.SetValue(sb, 20, null);
}
private PropertyInfo GetProperty(object obj, string property)
{
PropertyInfo info = obj.GetType().GetProperty(property);
if (info != null && info.CanRead && info.CanWrite)
return info;
return null;
}
I think only indexer properties can take parameters in C#. And I believe if you wrote properties in VB that take parameters and tried to reference that assembly in C# they would show up as methods instead of properties.
You could also write a function like this that would take 2 objects and a string for a property name and return the result of those properties matching:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info1 = obj1.GetType().GetProperty(propertyName);
PropertyInfo info2 = obj2.GetType().GetProperty(propertyName);
if (info1 != null && info1.CanRead && info2 != null && info2.CanRead)
return info1.GetValue(obj1, null).ToString() == info2.GetValue(obj2, null).ToString();
return false;
}
Comparing the values of the properties might be tricky because it would compare them as objects and who knows how equality will be handled for them. But converting the values to strings should work for you in this case.
If you know the 2 objects are the same type then you can simplify it:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info = obj1.GetType().GetProperty(propertyName);
if (info != null && info.CanRead)
return info.GetValue(obj1, null).ToString() == info.GetValue(obj2, null).ToString();
return false;
}
I think you're looking for something like:
public void SomeMethod<T>(T object, string propName)
where T : INotifyPropertyChanging, INotifyPropertyChanged
(
var type = typeof(T);
var property = type.GetProperty(propName);
if(property == null)
throw new ArgumentException("Property doesn't exist", "propName");
var value = property.GetValue(object, null);
)
I have a object[] containig some values. I want to extract infomation out of it, but I fail at casting the second object in the array (a WeakReference) to a IList with T as the third value in the array.
Take a look at my code:
object[] vals = GetValues(); //vals[2] = WeakReference, vals[3] = Type of T, vals[4] = index in the list
IList<((Type)vals[3])> list = (IList<((Type)vals[3])>)(((WeakReference)vals[2]).Target); //This line does not even compile, seems like I'm doing something wrong..
object oo = list.ElementAt((int)vals[4]);
//Do something with oo...
Any suggestions how I can cast the Target of the WeakReference to a IList interface with T = vals[3] ?
It's really strange that you are packing so much heterogeneous information into an array. Arrays are normally used to store elements of the same type. Why not encapsulate the data in a proper type?
But to answer the question as asked - in C# 4, you can use dynamic:
var target = ((dynamic)vals[2]).Target;
if(target != null)
{
object oo = Enumerable.ElementAt(target, vals[4]);
//Do something with oo...
}
(EDIT: If you want to minimize the use of dynamic here, cast to a WeakReference and leave the dynamic call to the end. This way, type-safety is 'maximized'.)
Otherwise, you can use reflection:
object target = ((WeakReference)vals[2]).Target;
if (target != null)
{
object oo = target.GetType()
.GetProperty("Item")
.GetValue(target, new[] { vals[4] });
//Do something with oo...
}
(EDIT: If the indexer could be explicitly implemented, you'll probably need to use the interface mappings.)
It was already suggested that you could use dynamic, but it sounds like you are also supposed to check that the object has the specified type. I’ve also kept use of dynamic to a minimum:
object target = ((WeakReference) vals[2]).Target;
if (target == null)
throw new InvalidOperationException("Target cannot be null.");
object result = Enumerable.ElementAt((dynamic) target, (int) vals[4]);
if (result != null && !((Type) vals[3]).IsAssignableFrom(result.GetType()))
throw new InvalidOperationException(string.Format("The retrieved object is a {0}, but the expected type was {1}.", result.GetType(), (Type) vals[3]));
return result;
If you just need the object from an enumerable, at a given index, here is a simple function that does it:
public static object GetObjectAt(IEnumerable enumerable, int index)
{
int i = 0;
foreach (object obj in enumerable)
{
if (i == index)
return obj;
i++;
}
throw new IndexOutOfRangeException();
}
And in your case, you would do this:
object oo = GetObjectAt((IEnumerable)(WeakReference)vals[2], (int)vals[4]);
Of course there are alternatives that look more sexy (see other answers), with fancy linq queries and cool C# 4 dynamic new trendy stuff :-) but, in general, if you don't "need" the T type (in your example code, you don't need it), you don't need generics. This solution is actually supported with any .NET Framework and C# versions, from 1 to 4.
I think you're working too hard to be able to use the extension methods which don't seem to be necessary.
object[] vals = GetValues();
var list = ((WeakReference)vals[2]).Target as IList;
object oo = null;
if (list != null)
{
oo = list[(int)vals[4]];
}
I'm currently trying to write a Dump() method from LinqPad equivalent iin C# for my own amusment. I'm moving from Java to C# and this is an exercise rather than a business requirement. I've got almost everything working except for Dumping a Dictionary.
The problem is that KeyValuePair is a Value type. For most other Value types I simply call the ToString method but this is insufficient as the KeyValuePair may contain Enumerables and other objects with undesirable ToString methods. So I need to work out if it's a KeyValuePair and then cast it. In Java I could use wildcard generics for this but I don't know the equivalent in C#.
Your quest, given an object o, determine if it's a KeyValuePair and call Print on its key and value.
Print(object o) {
...
}
Thanks!
If you don't know the types stored in the KeyValuePair you need to exercise a bit of reflection code.
Let's look at what is needed:
First, let's ensure the value isn't null:
if (value != null)
{
Then, let's ensure the value is generic:
Type valueType = value.GetType();
if (valueType.IsGenericType)
{
Then, extract the generic type definition, which is KeyValuePair<,>:
Type baseType = valueType.GetGenericTypeDefinition();
if (baseType == typeof(KeyValuePair<,>))
{
Then extract the types of the values in it:
Type[] argTypes = baseType.GetGenericArguments();
Final code:
if (value != null)
{
Type valueType = value.GetType();
if (valueType.IsGenericType)
{
Type baseType = valueType.GetGenericTypeDefinition();
if (baseType == typeof(KeyValuePair<,>))
{
Type[] argTypes = baseType.GetGenericArguments();
// now process the values
}
}
}
If you've discovered that the object does indeed contain a KeyValuePair<TKey,TValue> you can extract the actual key and value like this:
object kvpKey = valueType.GetProperty("Key").GetValue(value, null);
object kvpValue = valueType.GetProperty("Value").GetValue(value, null);
Presuming you are using the generic KeyValuePair then you need probably want to test for a particular instantiation, such as one created using a string for both key and value:
public void Print(object o)
{
if (o == null)
return;
if (o is KeyValuePair<string, string>)
{
KeyValuePair<string, string> pair = (KeyValuePair<string, string>)o;
Console.WriteLine("{0} = {1}", pair.Key, pair.Value);
}
}
If you want to test for any type of KeyValuePair then you'll need to use reflection. Do you?
you have the is keyword
http://msdn.microsoft.com/es-es/library/scekt9xw(VS.80).aspx