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
C# Date Formatting Is Losing Slash Separators
C# Linq Where Date Between 2 Dates
Prevent Textbox Autofill with Previously Entered Values
Writing to Then Reading from a Memorystream
Is CSV with Multi Tabs/Sheet Possible
Why Use Generic Constraints in C#
How to Set a Character at an Index in a String in C#
Performance of Nested Yield in a Tree
How to Pass Properties as "Out" or "Ref" Parameters
Getting Variable by Name in C#
How to Get Around Lack of Covariance with Ireadonlydictionary
C# - Static Types Cannot Be Used as Type Arguments
How to Initialize a Datetime Field