最近在用Linq的Distinct ,Except等方法是,遇到一個問題,就是這些方法都需要一個比較器才能跑出想要的東西
所以每當類型不同時都要自己寫個比較器,這樣下來一樣project下就會有好幾個比較器
所以我在想有沒有辦法寫一個通用的比較器呢?通過查詢學習,終於寫出了一個通用的比較器.
代碼如下:
代码
public
class
CommComparer
<
T
>
: IEqualityComparer
<
T
>
//
where T : struct,IQueryable
//
IComparable, IConvertible, IFormattable
{
private Func < T, T, bool > equals;
private Func < T, int > getHashCode;
private string _propName;
public CommComparer( string prop1)
{
_propName = prop1;
getHashCode = generateGetHashCode();
equals = generateEquals();
}
public CommComparer()
{
getHashCode = generateGetHashCode();
equals = generateEquals();
}
public bool Equals(T x, T y)
{
return equals(x, y);
}
public int GetHashCode(T obj)
{
return getHashCode(obj);
}
private Func < T, T, bool > generateEquals()
{
var xParam = Expression.Parameter( typeof (T), " x " );
var yParam = Expression.Parameter( typeof (T), " y " );
var getHashCodeMethod = typeof (T).GetMethod( " GetHashCode " );
switch ( typeof (T).Name)
{
case " DataRow " :
Func < ParameterExpression, MethodCallExpression > func = (param) =>
{
var fieldMethod = typeof (DataRowExtensions).GetMethods().First(m => m.Name == " Field " &&
m.IsGenericMethod).MakeGenericMethod( typeof ( object ));
var valueExpr = Expression.Constant(_propName, typeof ( string ));
var methodCallExpr = Expression.Call( null , fieldMethod, new Expression[] { param, valueExpr });
return methodCallExpr;
};
var xMethod = func(xParam);
var yMethod = func(yParam);
var equalExpression = Expression.Equal(Expression.Call(xMethod, getHashCodeMethod), Expression.Call(yMethod, getHashCodeMethod));
return Expression.Lambda < Func < T, T, bool >> (equalExpression, new [] { xParam, yParam }).Compile();
break ;
default :
if ( string .IsNullOrEmpty(_propName))
{
equalExpression = Expression.Equal(Expression.Call(xParam, getHashCodeMethod), Expression.Call(yParam, getHashCodeMethod));
return Expression.Lambda < Func < T, T, bool >> (equalExpression, new [] { xParam, yParam }).Compile();
}
else
{
var xPropExpr = Expression.Property(xParam, _propName);
var yPropExpr = Expression.Property(yParam, _propName);
equalExpression = Expression.Equal(Expression.Call(xPropExpr, getHashCodeMethod), Expression.Call(yPropExpr, getHashCodeMethod));
return Expression.Lambda < Func < T, T, bool >> (equalExpression, new [] { xParam, yParam }).Compile();
}
break ;
}
}
private Func < T, int > generateGetHashCode()
{
var objParam = Expression.Parameter( typeof (T), " obj " );
switch ( typeof (T).Name)
{
case " DataRow " :
Func < ParameterExpression, MethodCallExpression > func = (param) =>
{
var fieldMethod = typeof (DataRowExtensions).GetMethods().First(m => m.Name == " Field " &&
m.IsGenericMethod).MakeGenericMethod( typeof ( object ));
var valueExpr = Expression.Constant(_propName, typeof ( string ));
var methodCallExpr = Expression.Call(param, fieldMethod, new Expression[] { param, valueExpr });
return methodCallExpr;
};
var method = func(objParam);
var underlyingType = method.Type;
var getHashCodeMethod = underlyingType.GetMethod( " GetHashCode " );
var getHashCodeExpression = Expression.Call(method, getHashCodeMethod);
return Expression.Lambda < Func < T, int >> (getHashCodeExpression, new [] { objParam }).Compile();
break ;
default :
if ( string .IsNullOrEmpty(_propName))
{
underlyingType = objParam.Type;
getHashCodeMethod = underlyingType.GetMethod( " GetHashCode " );
getHashCodeExpression = Expression.Call(objParam, getHashCodeMethod);
return Expression.Lambda < Func < T, int >> (getHashCodeExpression, new [] { objParam }).Compile();
}
else
{
var objParamProp = Expression.Property(objParam, _propName);
underlyingType = objParamProp.Type;
getHashCodeMethod = underlyingType.GetMethod( " GetHashCode " );
getHashCodeExpression = Expression.Call(objParamProp, getHashCodeMethod);
return Expression.Lambda < Func < T, int >> (getHashCodeExpression, new [] { objParam }).Compile();
}
break ;
}
}
}
{
private Func < T, T, bool > equals;
private Func < T, int > getHashCode;
private string _propName;
public CommComparer( string prop1)
{
_propName = prop1;
getHashCode = generateGetHashCode();
equals = generateEquals();
}
public CommComparer()
{
getHashCode = generateGetHashCode();
equals = generateEquals();
}
public bool Equals(T x, T y)
{
return equals(x, y);
}
public int GetHashCode(T obj)
{
return getHashCode(obj);
}
private Func < T, T, bool > generateEquals()
{
var xParam = Expression.Parameter( typeof (T), " x " );
var yParam = Expression.Parameter( typeof (T), " y " );
var getHashCodeMethod = typeof (T).GetMethod( " GetHashCode " );
switch ( typeof (T).Name)
{
case " DataRow " :
Func < ParameterExpression, MethodCallExpression > func = (param) =>
{
var fieldMethod = typeof (DataRowExtensions).GetMethods().First(m => m.Name == " Field " &&
m.IsGenericMethod).MakeGenericMethod( typeof ( object ));
var valueExpr = Expression.Constant(_propName, typeof ( string ));
var methodCallExpr = Expression.Call( null , fieldMethod, new Expression[] { param, valueExpr });
return methodCallExpr;
};
var xMethod = func(xParam);
var yMethod = func(yParam);
var equalExpression = Expression.Equal(Expression.Call(xMethod, getHashCodeMethod), Expression.Call(yMethod, getHashCodeMethod));
return Expression.Lambda < Func < T, T, bool >> (equalExpression, new [] { xParam, yParam }).Compile();
break ;
default :
if ( string .IsNullOrEmpty(_propName))
{
equalExpression = Expression.Equal(Expression.Call(xParam, getHashCodeMethod), Expression.Call(yParam, getHashCodeMethod));
return Expression.Lambda < Func < T, T, bool >> (equalExpression, new [] { xParam, yParam }).Compile();
}
else
{
var xPropExpr = Expression.Property(xParam, _propName);
var yPropExpr = Expression.Property(yParam, _propName);
equalExpression = Expression.Equal(Expression.Call(xPropExpr, getHashCodeMethod), Expression.Call(yPropExpr, getHashCodeMethod));
return Expression.Lambda < Func < T, T, bool >> (equalExpression, new [] { xParam, yParam }).Compile();
}
break ;
}
}
private Func < T, int > generateGetHashCode()
{
var objParam = Expression.Parameter( typeof (T), " obj " );
switch ( typeof (T).Name)
{
case " DataRow " :
Func < ParameterExpression, MethodCallExpression > func = (param) =>
{
var fieldMethod = typeof (DataRowExtensions).GetMethods().First(m => m.Name == " Field " &&
m.IsGenericMethod).MakeGenericMethod( typeof ( object ));
var valueExpr = Expression.Constant(_propName, typeof ( string ));
var methodCallExpr = Expression.Call(param, fieldMethod, new Expression[] { param, valueExpr });
return methodCallExpr;
};
var method = func(objParam);
var underlyingType = method.Type;
var getHashCodeMethod = underlyingType.GetMethod( " GetHashCode " );
var getHashCodeExpression = Expression.Call(method, getHashCodeMethod);
return Expression.Lambda < Func < T, int >> (getHashCodeExpression, new [] { objParam }).Compile();
break ;
default :
if ( string .IsNullOrEmpty(_propName))
{
underlyingType = objParam.Type;
getHashCodeMethod = underlyingType.GetMethod( " GetHashCode " );
getHashCodeExpression = Expression.Call(objParam, getHashCodeMethod);
return Expression.Lambda < Func < T, int >> (getHashCodeExpression, new [] { objParam }).Compile();
}
else
{
var objParamProp = Expression.Property(objParam, _propName);
underlyingType = objParamProp.Type;
getHashCodeMethod = underlyingType.GetMethod( " GetHashCode " );
getHashCodeExpression = Expression.Call(objParamProp, getHashCodeMethod);
return Expression.Lambda < Func < T, int >> (getHashCodeExpression, new [] { objParam }).Compile();
}
break ;
}
}
}
調用方法如下:
1.對於control的比較,如果用ID來做比較,則代碼如下:
這個是屬性的調用方法:
代码
IEnumerable
<
WizardStepBase
>
differenceSteps
=
wizard1.WizardSteps.Cast
<
WizardStepBase
>
().Except(wizard2.WizardSteps.Cast
<
WizardStepBase
>
(),
new CommComparer < WizardStepBase > ( " ID " ));
new CommComparer < WizardStepBase > ( " ID " ));
2.如果比較的是DataRow ,而且比較的字段是"HIERARCHYNAME",則代碼如下:
那這個是方法的調用方法了.
var r
in
dt.AsEnumerable().Distinct(
new
CommComparer
<
DataRow
>
(
"
HIERARCHYNAME
"
))
這個比較器目前只滿足了我的需求,可能不完善,大家可以自己發揮,我只是拋磚引玉的作用吧