寫了個通用的比較器(comparer),應用动态生成Lambda(调用属性及方法)
最近在用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"))
這個比較器目前只滿足了我的需求,可能不完善,大家可以自己發揮,我只是拋磚引玉的作用吧