C# Compare Two Generic Values

c# compare two generic values

You cannot use operators on generic types (except for foo == null which is special cased) unless you add where T : class to indicate it is a reference type (then foo == bar is legal)

Use EqualityComparer<T>.Default to do it for you. This will not work on types which only supply an operator overload for == without also either:

  • implement IEquatable<T>
  • overrides object.Equals()

In general implementing the == operator and not also doing at least one of these would be a very bad idea anyway so this is not likely to be an issue.

public bool IsDataChanged<T>()
{
T value1 = GetValue2;
T value2 = GetValue1();

return !EqualityComparer<T>.Default.Equals(value1 , value2);
}

If you do not restrict to IEquatable<T> then the EqualityComparer default fallback may cause boxing when used with value types if they do not implement IEquatable<T> (if you control the types which are being used this may not matter). I am assuming you were using =! for performance though so restricting to the Generic type will avoid accidental boxing via the Object.Equals(object) route.

Generic solution to compare two generic list and type known only on run time

Your easiest solution of all would be to implement IEquatable<T> on your 27 different types. Then you can use the regular equals operators (dataFromExcel.Equals(dataFromTable) or dataFromExcel == dataFromTable. However, if you need to be able to do anything with the values during the process, there are other options you have.

Using an idea from this answer, you can get this without having to use reflection. Utilize the Newtonsoft JSON.NET library to do the "heavy lifting" for you, and keep your code readable.

The one thing you'd want to do is restrict the type of each list to the same type. Your method would look something like this:

private bool CompareTwoObjects<T>(T one, T two)
{
var json1 = JObject.FromObject(one);
var json2 = JObject.FromObject(two);

foreach (JProperty prop1 in json1.Properties())
{
var prop2 = json2.Properties().First(p => p.Name == prop1.Name);

if (prop1.Value != prop2.Value)
{
return false;
}
}

return true;
}

Seeing in your comment that you want to compare a collection of each, you can still utilize both options.

IEquatable<T> method:

var allAreEqual = dataFromExcel.All(one => dataFromTable.Any(two => one == two));

Custom method:

var allAreEqual = dataFromExcel(one => dataFromTable.Any(two => CompareTwoObjects(one, two));

I'm sure there's some optimization that you can do here to reduce the N factor, but this points you in the right direction.

Comparing Two values in a generic method c#

You could use Comparer<T>.Default.Compare(operatorOne, operatorTwo) for comparation. Please be aware that if T does not implement IComparable and IComparable<T>, Comparer<T>.Default.Compare throws an exception.

To make sure that T implements IComparable, you may add where T: IComparable constraint. (It will exclude classes which implement IComparable<T>, but not IComparable. Still may be acceptable, since many classes which implement IComparable<T>, implement IComparable too.)

private bool Comparison<T>(T operatorOne, T operatorTwo, string operand)
where T: IComparable
{
switch(operand.ToLower())
{
case "=":
return Comparer<T>.Default.Compare(operatorOne, operatorTwo) == 0;
case "<":
return Comparer<T>.Default.Compare(operatorOne, operatorTwo) < 0;
case ">":
return Comparer<T>.Default.Compare(operatorOne, operatorTwo) > 0;
case "contains":
return operatorOne.ToString().Contains(operatorTwo.ToString());
default:
return false;
}
}

P.S.

As Servy suggested, you may also pass IComparer as an extra parameter to the function. It would allow to cover types which implement neither IComparable nor IComparable<T>, so Comparer<T>.Default does not work for them.

Also, credits go to @TimothyShields, who suggested Comparer<T>.Default.

How to determine if two generic type values are equal?

As suggested in Marc Gravell's answer, the problem is with StringBuilder Equals(object) implementation that is different to the one in Equals(StringBuilder).

Then, you can ignore the problem because your code will work with any other coherently-implemented classes, or you can use dynamic to fix the problem (again as suggested by Mark Gravell).

But, given that you are not using C# 4 (so no dynamic), you can try in this way:

public bool Equals(T value)
{
// uses Reflection to check if a Type-specific `Equals` exists...
var specificEquals = typeof(T).GetMethod("Equals", new Type[] { typeof(T) });
if (specificEquals != null &&
specificEquals.ReturnType == typeof(bool))
{
return (bool)specificEquals.Invoke(this.Value, new object[]{value});
}
return this.Value.Equals(value);
}

How I can compare two values of same generic type?

The IComparable interface that you have used here as the type constraint gives you a CompareTo method. So you can do something like this:

public bool IsGreater(T t1, T t2)
{
return t1.CompareTo(t2) > 0;
}

Compare two generic lists using Linq

Note : The return type of your Linq Query will be IEnumerable you need to not create it again by casting;

Have you tried something like this:

public IEnumerable<SalesOrder> GetModifiedRecords(IEnumerable<SalesOrder> oldSalesOrderList, List<SalesOrder> newSalesOrderList)
{
return oldSalesOrderList.Where((x,i)=>newSalesOrderList[i].Value !=x.Value);
}

Above code will works only if both Lists are of same order, if not you can try something like this(Assume that OrderId will be an unique field):

return oldSalesOrderList.Where(x =>
newSalesOrderList.Any(y => y.OrderId == x.OrderId && Y.Value !=x.Value));


Related Topics



Leave a reply



Submit