Find an identical function signature with different name - c#

Given an object and an instance method, I want to get a method that has the exact same signature but with a different, known name. That includes parameter list, generic parameters, possibly attributes if they're a part of the signature. How can I do that?
I know GetMethod() exists but I couldn't figure out which overload covers all the different possible signature variations.

Something like this may work in some cases:
public static bool HasSameSignature(MethodInfo m1, MethodInfo m2)
{
if (m1.GetGenericArguments().Length != m2.GetGenericArguments().Length)
return false;
var args1 = m1.GetParameters();
var args2 = m2.GetParameters();
if (args1.Length != args2.Length)
return false;
for (var idx = 0; idx < args1.Length; idx++)
{
if (!AreEquivalentTypes(args1[idx].ParameterType, args2[idx].ParameterType))
return false;
}
return true;
}
static bool AreEquivalentTypes(Type t1, Type t2)
{
if (t1 == null || t2 == null)
return false;
if (t1 == t2)
return true;
if (t1.DeclaringMethod != null && t2.DeclaringMethod != null && t1.GenericParameterPosition == t2.GenericParameterPosition)
return true;
if (AreEquivalentTypes(t1.GetElementType(), t2.GetElementType()))
return true;
if (t1.IsGenericType && t2.IsGenericType && t1.GetGenericTypeDefinition() == t2.GetGenericTypeDefinition())
{
var ta1 = t1.GenericTypeArguments;
var ta2 = t2.GenericTypeArguments;
for (var idx = 0; idx < ta1.Length; idx++)
{
if (!AreEquivalentTypes(ta1[idx], ta2[idx]))
return false;
}
return true;
}
return false;
}
So given your one method, you can do .GetMethods() on the type in question, and find the one whose name is correct, and for which HasSameSignature(...) on it and your one given method is true.
Type givenType = ...;
MethodInfo givenMethod = ...;
string givenDifferentName = ...;
var answer = givenType.GetMethods()
.SingleOrDefault(m => m.Name == givenDifferentName && HasSameSignature(m, givenMethod));

Related

Method invoke is returning 'parameter count mismatch' as error

I want to call a method by string. I got quite far until my code returns parameter count mismatch.
I know that neither my classInstance nor my method is null.
I read that you need to put your Parameterarray into another array.
It seems just perfect, but then it gives me this error.
The class of the method is located at Modules.Achievements.Achieve.
methodname is the variable string that would equal with an existing method in the Achieve class.
string userid = Modules.Users.GetCreatorId();
var type = typeof(Modules.Achievements.Achieve);
MethodInfo method = type.GetMethod(methodname);
try
{
if ( method == null )
return;
object classInstance = Activator.CreateInstance(type, null);
if ( classInstance == null )
return;
object[] parametersArray = new object[] { userid };
var result = (Boolean)method.Invoke(classInstance,
new object[] { parametersArray });
if ( result )
{
Console.WriteLine("succeeded.");
return;
}
Console.WriteLine("incorrect steamid.");
return;
}
catch ( Exception e )
{
Console.WriteLine($"error:{e.Message}");
}
Console.WriteLine("failed.");
return;
My method should return a Boolean if something failed or not.
The method only has one Parameter (String). In this case it is the userid that goes into the method as parameter.
Instead of returning anything, it detects an error before returning something.
The error is from the method.Invoke(classInstance, new object[] { parametersArray });.
I googled parameter count mismatch on Reflection but all solutions I saw still give the same error.
What can I do best?
Sins not a lot of useful info is provided, your best bet would be to do something like this to fix up the parameters, also your parametersArray should be passed in without it being part of another array.
public void InvokeMethod()
{
var type = typeof(Modules.Achievements.Achieve);
var method = type.GetMethod(methodname);
if (method != null)
{
var instance = Activator.CreateInstance(type, null);
if (instance != null)
{
var fixedParams = ParseParameters(method.GetParameters(), new object[] { Modules.Users.GetCreatorId() });
if ((bool)method.Invoke(instance, fixedParams))
{
Console.WriteLine("Success");
}
else
{
Console.WriteLine("Invalid Steam ID");
}
return;
}
}
Console.WriteLine("Encountered an error!");
}
private object[] ParseParameters(ParameterInfo[] methodParams, object[] userParams)
{
int mLength = methodParams.Length;
if (mLength > 0)
{
var objs = new object[mLength];
if ((userParams == null) || (userParams.Length == 0))
{
for (int i = 0; i < mLength; i++)
{
var mp = methodParams[i];
objs[i] = (mp.HasDefaultValue ? mp.DefaultValue : mp.ParameterType.IsClass ? null : Activator.CreateInstance(mp.ParameterType, null));
}
}
else
{
int uLength = userParams.Length;
if (uLength > mLength) { throw new ArgumentException("Too many params were specified"); }
for (int i = 0; i < uLength; i++)
{
objs[i] = Convert.ChangeType(userParams[i], methodParams[i].ParameterType);
}
if (uLength < mLength)
{
for (int i = uLength; i < mLength; i++)
{
var mp = methodParams[i];
objs[i] = (mp.HasDefaultValue ? mp.DefaultValue : mp.ParameterType.IsClass ? null : Activator.CreateInstance(mp.ParameterType, null));
}
}
}
return objs;
}
return null;
}

Generic Compare function [duplicate]

This question already has answers here:
Check two object, of unknown type, for equality, comparing all their fields
(2 answers)
Closed 3 years ago.
I'm trying to make a generic compare function to see if two instances of a class which may hold member variables that are a List<>.
bool IsEqual<T>(T a, T b)
{
var props = typeof(T).GetProperties();
foreach(var property in props)
{
var aVal = property.GetValue(a);
var bVal = property.GetValue(b);
if (aVal as System.Collections.IEnumerable != null)
{
// Convert into lists, do something with SequenceEqual and possibly recursive call to IsEqual
}
if (!Equals(aVal,bVal)) return false;
}
return true;
}
I'm not sure how to convert a given member variable to a proper list, so I can do a SequenceEqual on it to compare the lists.
The classes that I will use in IsEqual() are not native to my program but comes from a DLL.
Does the following code work for you?
public static bool DeepEquals(object a, object b)
{
if (a == null)
{
if (b == null) return true;
else return false;
}
else if (b == null) return false;
if (object.ReferenceEquals(a, b)) return true;
var comparable = a as IComparable;
if (comparable != null)
{
return comparable.CompareTo(b) == 0;
}
var aType = a.GetType();
var bType = b.GetType();
if (aType != bType) return false;
var aEnumerable = a as IEnumerable;
if (aEnumerable != null)
{
var bEnumerable = (IEnumerable)b;
var aEnumerator = aEnumerable.GetEnumerator();
var bEnumerator = bEnumerable.GetEnumerator();
while (true)
{
var amoved = aEnumerator.MoveNext();
var bmoved = bEnumerator.MoveNext();
if (amoved != bmoved) return false;
if (amoved == false && bmoved == false) return true;
if (DeepEquals(aEnumerator.Current, bEnumerator.Current) == false) return false;
}
}
var props = aType.GetProperties();
foreach (var prop in props)
{
if (DeepEquals(prop.GetValue(a), prop.GetValue(b)) == false) return false;
}
return true;
}
Note that this method is not generic. Implementing a generic method is more difficult because you don't know at runtime the type of properties nor the type of the items of collections.

How to I convert from Type.FullName to a C# type name?

Examples,
"Namespace.ClassName+NestedClassName" becomes "Namespace.ClassName.NestedClassName".
"System.Collections.Generic.List`1[System.String]" becomes "System.Collections.Generic.List".
I need this for a code generator and I don't want to do a simple RegEx replace because of edge cases such as type names with '+' symbols in them. (Yes, though stupid that is possible.)
/// <summary>
/// Gets the fully quantified name in C# format.
/// </summary>
public string CSharpFullName
{
get
{
if (m_CSharpFullName == null)
{
var result = new StringBuilder(m_TypeInfo.ToString().Length);
BuildCSharpFullName(m_TypeInfo.AsType(), null, result);
m_CSharpFullName = result.ToString();
}
return m_CSharpFullName;
}
}
static void BuildCSharpFullName(Type typeInfo, List<Type> typeArgs, StringBuilder result)
{
var localTypeParamCount = typeInfo.GetTypeInfo().GenericTypeParameters.Length;
var localTypeArgCount = typeInfo.GetTypeInfo().GenericTypeArguments.Length;
var typeParamCount = Math.Max(localTypeParamCount, localTypeArgCount);
if (typeArgs == null)
typeArgs = new List<Type>(typeInfo.GetTypeInfo().GenericTypeArguments);
if (typeInfo.IsNested)
{
BuildCSharpFullName(typeInfo.DeclaringType, typeArgs, result);
}
else
{
result.Append(typeInfo.Namespace);
}
result.Append(".");
foreach (var c in typeInfo.Name)
{
if (c == '`') //we found a generic
break;
result.Append(c);
}
if (localTypeParamCount > 0)
{
result.Append("<");
for (int i = 0; i < localTypeParamCount; i++)
{
if (i > 0)
result.Append(",");
BuildCSharpFullName(typeArgs[i], null, result); //note that we are "eating" the typeArgs that we passed to us from the nested type.
}
typeArgs.RemoveRange(0, localTypeParamCount); //remove the used args
result.Append(">");
}
else if (localTypeArgCount > 0 && typeArgs.Count > 0)
{
result.Append("<");
for (int i = 0; i < Math.Min(localTypeArgCount, typeArgs.Count); i++)
{
if (i > 0)
result.Append(",");
BuildCSharpFullName(typeArgs[i], null, result);
}
result.Append(">");
}
}
You could use Type.GetType to parse the string into a Type object. From there you could use GetGenericArguments and other members to get the Type info of the individual components. You could use those to reconstruct your target string.

Resharper Search with pattern method call

I want to replace this part of code using "Search with pattern...":
public bool IsDbObjectsOK()
{
var result = 0;
result = usp_IsDbObjectsOK();
if (result == 0)
return true;
return false;
}
public bool UnlockWindow()
{
var result = 0;
result = usp_UnlockWindow();
if (result == 0)
return true;
return false;
}
Replace with:
public bool IsDbObjectsOK()
{
return usp_IsDbObjectsOK() == 0;
}
public bool UnlockWindow()
{
return usp_UnlockWindow() == 0;
}
I tried to use
var $result$ = 0;
$result$ = $usp_IsDbObjectsOK$();
if ($result$ == 0)
return true;
return false;
This doesn't work, because the method call isn't found in any of the code that needs to be replaced.
How to do this?
You need to make sure that you use the correct placeholder type when you set up the search.
Here, result should be an Identifier Placeholder and usp_IsDbObjectsOK should be an Expression Placeholder. When I do that, the replace works as you'd expect.

Compare the content of two objects for equality

I have two complex (i.e. objects with string, int, double, List and other home made data type) objects of the same type. I would like to compare the content of both of them to ensure that they are identical. Note: The object doesn't implement .Equals (I have no control on that) and doesn't implement IComparable.
Is there a generic way (reflection?) to compare the content of the two objects?
Thanks!
I have created a class to perform a deep compare of .NET Objects. See:
https://github.com/GregFinzer/Compare-Net-Objects
My Working solution.!
private bool Compare(object obj1, object obj2)
{
if (obj1 == null || obj2 == null)
{
return false;
}
if (!obj1.GetType().Equals(obj2.GetType()))
{
return false;
}
Type type = obj1.GetType();
if (type.IsPrimitive || typeof(string).Equals(type))
{
return obj1.Equals(obj2);
}
if (type.IsArray)
{
Array first = obj1 as Array;
Array second = obj2 as Array;
var en = first.GetEnumerator();
int i = 0;
while (en.MoveNext())
{
if (!Compare(en.Current, second.GetValue(i)))
return false;
i++;
}
}
else
{
foreach (PropertyInfo pi in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
var val = pi.GetValue(obj1);
var tval = pi.GetValue(obj2);
if (!Compare(val, tval))
return false;
}
foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
var val = fi.GetValue(obj1);
var tval = fi.GetValue(obj2);
if (!Compare(val, tval))
return false;
}
}
return true;
}
Hope it helps.!
I just wrote my version. This function use generic and reflection. It works by recursive it self until all of things in the object already compare or found one that do not equal.
public class Utils
{
public bool CompareObjects<T>(T expectInput, T actualInput)
{
// If T is primitive type.
if (typeof(T).IsPrimitive)
{
if (expectInput.Equals(actualInput))
{
return true;
}
return false;
}
if (expectInput is IEquatable<T>)
{
if (expectInput.Equals(actualInput))
{
return true;
}
return false;
}
if (expectInput is IComparable)
{
if (((IComparable)expectInput).CompareTo(actualInput) == 0)
{
return true;
}
return false;
}
// If T is implement IEnumerable.
if (expectInput is IEnumerable)
{
var expectEnumerator = ((IEnumerable)expectInput).GetEnumerator();
var actualEnumerator = ((IEnumerable)actualInput).GetEnumerator();
var canGetExpectMember = expectEnumerator.MoveNext();
var canGetActualMember = actualEnumerator.MoveNext();
while (canGetExpectMember && canGetActualMember && true)
{
var currentType = expectEnumerator.Current.GetType();
object isEqual = typeof(Utils).GetMethod("CompareObjects").MakeGenericMethod(currentType).Invoke(null, new object[] { expectEnumerator.Current, actualEnumerator.Current });
if ((bool)isEqual == false)
{
return false;
}
canGetExpectMember = expectEnumerator.MoveNext();
canGetActualMember = actualEnumerator.MoveNext();
}
if (canGetExpectMember != canGetActualMember)
{
return false;
}
return true;
}
// If T is class.
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
var expectValue = typeof(T).GetProperty(property.Name).GetValue(expectInput);
var actualValue = typeof(T).GetProperty(property.Name).GetValue(actualInput);
if (expectValue == null || actualValue == null)
{
if (expectValue == null && actualValue == null)
{
continue;
}
return false;
}
object isEqual = typeof(Utils).GetMethod("CompareObjects").MakeGenericMethod(property.PropertyType).Invoke(null, new object[] { expectValue, actualValue });
if ((bool)isEqual == false)
{
return false;
}
}
return true;
}
}
Is there a generic way to compare the content of the two objects?
Well yes, but generally that's known as the IComparable interface.
If you could descend from the class and create a child that implemented IComparable, that might be ideal.
Reflection would be it, but the issue is the contained types - for example, you can't just use Equals or EqualityComparer<T>, since the sub-data also won't be conveniently comparable if it is a List<T> etc.
How often do you need to do this? Could you serialize them and compare the serialized value? That might be the most robust option.
GetHashcode works for me.
I override GetHashcode() in every class with all public relevant properties X-OR-ed
e.g.
override GetHashCode()
{
return A.GetHashCode() ^ B.GetHashCode ^ C.SafeString().Get..
}
I iterate this through all classes, again X-OR the values.
IsModified compares a previously HashValue with the current.
Two different objects could indeed return the same HashValue, with a chance of 1 to 4 billion, but for many purposes this is good enough for me.
But I have an even better idea, using a MemoryStream
here is an Extension:
public static bool IsBinaryEqualTo(this object obj, object obj1)
{
using (MemoryStream memStream = new MemoryStream())
{
if (obj == null || obj1 == null)
{
if (obj == null && obj1 == null)
return true;
else
return false;
}
BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, obj);
byte[] b1 = memStream.ToArray();
memStream.SetLength(0);
binaryFormatter.Serialize(memStream, obj1);
byte[] b2 = memStream.ToArray();
if (b1.Length != b2.Length)
return false;
for (int i = 0; i < b1.Length; i++)
{
if (b1[i] != b2[i])
return false;
}
return true;
}
}
The fastest and easiest way I've found is to serialize both objects using MessagePack then compare the byte arrays.
public static bool DeepEquals(object o1, object o2)
{
var b1 = MessagePackSerializer.Serialize(o1, ContractlessStandardResolver.Instance);
var b2 = MessagePackSerializer.Serialize(o2, ContractlessStandardResolver.Instance);
return b1.SequenceEqual(b2);
}
Serialize the objects to XML string and you can end up doing a string comparison between the 2 objects that are serialized...
private string Serialize<T>(T value)
{
if (value == null)
{
return string.Empty;
}
try
{
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
StringWriter stringWriter = new StringWriter();
XmlWriter writer = XmlWriter.Create(stringWriter);
xmlserializer.Serialize(writer, value);
string serializeXml = stringWriter.ToString();
writer.Close();
return serializeXml;
}
catch (Exception ex)
{
return string.Empty;
}
}
}
For my last project I made a nice deep compair with some features.
public class ObjektHelper
{
/// <summary>
/// Compairs two Objects and gives back true if they are equal
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj1">Object 1</param>
/// <param name="obj2">Object 2</param>
/// <param name="consideredFieldNames">If the list is not mepty, only the field within equal names are compaired.</param>
/// <param name="notConsideredFieldNames">If you want not compair some fields enter their name in this list.</param>
/// <returns></returns>
public static bool DeepCompare<T>(T obj1, T obj2, string[] consideredFieldNames, params string[] notConsideredFieldNames)
{
var errorList = new List<object>();
if (notConsideredFieldNames == null) notConsideredFieldNames = new[] {""};
DeepCompare(obj1, obj2, errorList, consideredFieldNames, notConsideredFieldNames, false);
return errorList.Count <= 0;
}
/// <summary>
/// Compairs two Objects and gives an error list back.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj1"></param>
/// <param name="obj2"></param>
/// <param name="errorList">The error list gives back the names of the fields that are not equal.</param>
/// <param name="consideredFieldNames">If the list is not mepty, only the field within equal names are compaired.</param>
/// <param name="notConsideredFieldNames">If you want not compair some fields enter their name in this list.</param>
/// <param name="endWithErrors">If the value is false, the method end at the first error.</param>
public static void DeepCompare<T>(T obj1, T obj2, List<object> errorList, string[] consideredFieldNames, string[] notConsideredFieldNames, bool endWithErrors)
{
if (errorList == null) throw new Exception("errorListliste ist NULL");
if (Equals(obj1, default(T)) && Equals(obj2, default(T))) return;
if (Equals(obj1, default(T)) || Equals(obj2, default(T)))
{
errorList.Add("One of the object are null!");
return;
}
if (!endWithErrors && errorList != null && errorList.Count > 0) throw new Exception("ErrorListliste is not empty");
var type1 = obj1.GetType();
var type2 = obj2.GetType();
var propertyInfos1 = type1.GetProperties();
var propertyInfos2 = type2.GetProperties();
// To use the access via index, the list have to be ordered!
var propertyInfoOrdered1 = propertyInfos1.OrderBy(p => p.Name).ToArray();
var propertyInfoOrdered2 = propertyInfos2.OrderBy(p => p.Name).ToArray();
if (type1 != type2) errorList.AddRange(new List<object> {type1, type2});
else
{
for (var i = 0; i < propertyInfos1.Length; i++)
{
var t1 = propertyInfoOrdered1[i].PropertyType;
var t2 = propertyInfoOrdered2[i].PropertyType;
if (t1 != t2)
{
errorList.AddRange(new List<object> {type1, type2});
continue;
}
var name1 = propertyInfoOrdered1[i].Name;
var name2 = propertyInfoOrdered2[i].Name;
// Use the next 4 lines to find a bug
//if (name1 == "Enter name of field with the bug")
// Console.WriteLine(name1);
//if (name2 == "Enter name of field1 with the bug" || name2 == "Enter name of field2 with the bug")
// Console.WriteLine(name2);
if (consideredFieldNames != null && !consideredFieldNames.Contains(name1)) continue;
if (notConsideredFieldNames != null && notConsideredFieldNames.Contains(name1)) continue;
var value1 = propertyInfoOrdered1[i].GetValue(obj1, null);
var value2 = propertyInfoOrdered2[i].GetValue(obj2, null);
// check Attributes
var guiName1 = (propertyInfoOrdered1[i].GetCustomAttributes().FirstOrDefault(a => a.GetType() == typeof(GuiNameofModelAttribute)) as GuiNameofModelAttribute)?.GuiName;
var guiName2 = (propertyInfoOrdered2[i].GetCustomAttributes().FirstOrDefault(a => a.GetType() == typeof(GuiNameofModelAttribute)) as GuiNameofModelAttribute)?.GuiName;
// create errorListrange
var temperrorListRange = new List<object>();
if (guiName1 != null && guiName2 != null) temperrorListRange.AddRange(new List<object> { guiName1, guiName2 });
else temperrorListRange.AddRange(new List<object> { propertyInfoOrdered1[i], propertyInfoOrdered2[i] });
// both fields are null = OK
if ((value1 == null && value2 == null) || (value1 is Guid && value2 is Guid)) continue;
// one of the fields is null = errorList
if (value1 == null || value2 == null) errorList.AddRange(temperrorListRange);
// Value types, Enum and String compair
else if (t1.BaseType == typeof (ValueType) || t1.BaseType == typeof (Enum) || t1 == typeof (string))
{
if (!value1.Equals(value2)) errorList.AddRange(temperrorListRange);
}
// List, array, generic lists, collection and bindinglist compair
else if (t1 == typeof (Array) || (t1.IsGenericType && (t1.GetGenericTypeDefinition() == typeof (List<>) ||
t1.GetGenericTypeDefinition() == typeof (IList<>) ||
t1.GetGenericTypeDefinition() == typeof (Collection<>) ||
t1.GetGenericTypeDefinition() == typeof (ICollection<>) ||
t1.GetGenericTypeDefinition() == typeof (ObservableCollection<>) ||
t1.GetGenericTypeDefinition() == typeof (BindingList<>) ||
t1.GetGenericTypeDefinition() == typeof (BindingList<>)
)))
DeepListCompare(value1 as IEnumerable<object>, value2 as IEnumerable<object>, errorList, consideredFieldNames, notConsideredFieldNames, endWithErrors);
// Clas compair
else if (t1.IsClass || t1.IsAnsiClass) DeepCompare(value1, value2, errorList, consideredFieldNames, notConsideredFieldNames, endWithErrors);
else throw new NotImplementedException();
if (!endWithErrors && errorList.Count > 0) break;
}
}
} // End DeepCompare<T>
/// <summary>
/// Compairs two lists and gives back true if they are equal.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tlist1">Generic list 1</param>
/// <param name="tlist2">Generic List 2</param>
/// <returns></returns>
public static bool DeepListCompare<T>(T tlist1, T tlist2)
{
var errorList = new List<object>();
DeepCompare(tlist1, tlist2, errorList, null, null, false);
return errorList.Count <= 0;
}
/// <summary>
/// Compairs two lists and gives backthe error list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tlist1">Generic list 1</param>
/// <param name="tlist2">Generic list 2</param>
/// <param name="errorList">The error list gives back the names of the fields that are not equal.</param>
/// <param name="consideredFieldNames">If the list is not mepty, only the field within equal names are compaired.</param>
/// <param name="notConsideredFieldNames">If you want not compair some fields enter their name in this list.</param>
/// <param name="endWithErrors">If the value is false, the method end at the first error.</param>
public static void DeepListCompare<T>(T tlist1, T tlist2, List<object> errorList, string[] consideredFieldNames, string[] notConsideredFieldNames, bool endWithErrors)
where T : IEnumerable<object>
{
if (errorList == null) throw new Exception("errorListliste ist NULL");
if (!endWithErrors && errorList.Count > 0) throw new Exception("errorListliste ist nicht Leer");
if (Equals(tlist1, null) || Equals(tlist2, null))
{
errorList.AddRange(new List<object> {tlist1, tlist2});
return;
}
var type1 = tlist1.GetType();
var type2 = tlist2.GetType();
var propertyInfos1 = type1.GetProperties();
var propertyInfos2 = type2.GetProperties();
// To use the access via index, the list have to be ordered!
var propertyInfoOrdered1 = propertyInfos1.OrderBy(p => p.Name).ToArray();
var propertyInfoOrdered2 = propertyInfos2.OrderBy(p => p.Name).ToArray();
for (var i = 0; i < propertyInfos1.Length; i++)
{
var t1 = propertyInfoOrdered1[i].PropertyType;
var t2 = propertyInfoOrdered2[i].PropertyType;
if (t1 != t2) errorList.AddRange(new List<object> {t1, t2});
else
{
// Kick out index
if (propertyInfoOrdered1[i].GetIndexParameters().Length != 0)
{
continue;
}
// Get value
var value1 = propertyInfoOrdered1[i].GetValue(tlist1, null) as IEnumerable<object>;
var value2 = propertyInfoOrdered2[i].GetValue(tlist2, null) as IEnumerable<object>;
if (value1 == null || value2 == null) continue;
// Only run through real lists.
if (t1 == typeof (Array) ||
t1.IsGenericType && t1.GetGenericTypeDefinition() == typeof (List<>) ||
t1.IsGenericType && t1.GetGenericTypeDefinition() == typeof (Collection<>))
{
// cast
var objectList1 = value1.ToList();
var objectList2 = value2.ToList();
if (objectList1.Count == 0 && objectList1.Count == 0)
{
//errorList.AddRange(new List<Object> { objectList1, objectList1 });
continue;
}
foreach (var item1 in objectList1)
{
foreach (var item2 in objectList2)
{
var temperrorListCount = errorList.Count;
DeepCompare(item1, item2, errorList, consideredFieldNames, notConsideredFieldNames, endWithErrors);
if (temperrorListCount != errorList.Count) continue;
objectList2.Remove(item2);
break;
}
if (!endWithErrors && errorList.Count > 0) break;
}
}
else DeepCompare(value1, value2, errorList, consideredFieldNames, notConsideredFieldNames, endWithErrors);
}
if (!endWithErrors && errorList.Count > 0) break;
}
} // End DeepListCompare<T>
} // end class ObjectHelper
[AttributeUsage(AttributeTargets.All)]
public class GuiNameofModelAttribute : Attribute
{
public readonly string GuiName;
public GuiNameofModelAttribute(string guiName)
{
GuiName = guiName;
}
}
You could simply write a utility method in another class to do the comparison. However, that is assuming the properties of the class in question are publicly accessible. Are they?
Thanks for the MemoryStream approach, Marc. I thought sure there was a mistake in when I saw "this" in the arguments, but surprisingly the compiler actually lets you do it that way, huh? I made a slight change and chose to override to Equals() instead. Kudos also for using length and array comparison rather than SequenceEquals(). Takes an extra minute to write, but according to http://www.dotnetperls.com/sequenceequal, the performance is much better.
public override bool Equals(object obj)
{
// If comparison object is null or is a different type, no further comparisons are necessary...
if (obj == null || GetType() != obj.GetType())
{
return false;
}
// Compare objects using byte arrays...
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
// Get byte array of "this" object...
binaryFormatter.Serialize(memStream, this);
byte[] b1 = memStream.ToArray();
// Get byte array of object to be compared...
memStream.SetLength(0);
binaryFormatter.Serialize(memStream, obj);
byte[] b2 = memStream.ToArray();
// Compare array sizes. If equal, no further comparisons are necessary...
if (b1.Length != b2.Length)
return false;
// If sizes are equal, compare each byte while inequality is not found...
for (int i = 0; i < b1.Length; i++)
{
if (b1[i] != b2[i])
return false;
}
}
return true;
}
Well, you could write some logic to compare all of the properties of the two objects to each other. This gets complicated when it is an object graph with complex subtypes, so you will need to determine how close is good enough.
You would need a compare method of something else; in C++ you could just write a global function, but I don't think c# allows that, just as Java doesn't.
What I'd do is write a class that implements iComparable, and has a ctor that takes an object of your desired class, and includes your Equals function. Set it up so all it keeps is a reference to the original object, to save mallocations.
Then you can write
Foo(A).Equals(new Foo(B))
You could instead inherit from the provided class, but that would mean needing to create and track these things.

Categories

Resources