風之力

导航

寫了個通用的比較器(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;
            }
        }
    }

 

調用方法如下:

1.對於control的比較,如果用ID來做比較,則代碼如下:

這個是屬性的調用方法:

代码
 IEnumerable<WizardStepBase> differenceSteps = wizard1.WizardSteps.Cast<WizardStepBase>().Except(wizard2.WizardSteps.Cast<WizardStepBase>(),
                    
new CommComparer<WizardStepBase>("ID"));

 

 

2.如果比較的是DataRow ,而且比較的字段是"HIERARCHYNAME",則代碼如下:

那這個是方法的調用方法了.

var r in dt.AsEnumerable().Distinct(new CommComparer<DataRow>("HIERARCHYNAME"))

 

 

這個比較器目前只滿足了我的需求,可能不完善,大家可以自己發揮,我只是拋磚引玉的作用吧

 

 

posted on 2010-01-08 22:14  ZY.Zhou  阅读(458)  评论(0编辑  收藏  举报