Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 表达式树的动态LINQ查询_C#_Lambda_Expression Trees - Fatal编程技术网

C# 表达式树的动态LINQ查询

C# 表达式树的动态LINQ查询,c#,lambda,expression-trees,C#,Lambda,Expression Trees,我试图根据LINQ查询中的条件返回具有更新属性的实体。下面是查询,运行良好 public class SampleDataModel { public string Name { get; set; } public string Group { get; set; } public int? Hyper { get; set; } public string Sin { ge

我试图根据LINQ查询中的条件返回具有更新属性的实体。下面是查询,运行良好

    public class SampleDataModel
        {
            public string Name { get; set; }
            public string Group { get; set; }
            public int? Hyper { get; set; }
            public string Sin { get; set; }
            public int? Auto { get; set; }

            public string Comment
            {
                get { return (Auto.HasValue ? "Hyper & Name should be masked" : ""); }
            }

            public override string ToString()
            {
                return $"Group={Group};Name={Name};Hyper={Hyper};Sin={Sin};Auto={Auto};Comment={Comment}";
            }
        }

        public class SampleData
        {
            private static readonly IList<SampleDataModel> Data = new List<SampleDataModel>();

            static SampleData()
            {
                Data.Add(new SampleDataModel()
                    {Name = "Name 1", Group = "Group 11", Hyper = 10, Sin = "S12345986554", Auto = 1});
                Data.Add(new SampleDataModel()
                    {Name = "Name 2", Group = "Group 12", Hyper = 101, Sin = "MS7123452331", Auto = 19});
                Data.Add(new SampleDataModel()
                    {Name = "Name 3", Group = "Group 13", Hyper = 103, Sin = "SJK1234Z5666", Auto = 18});
                Data.Add(new SampleDataModel()
                    {Name = "Name 4", Group = "Group 14", Hyper = 210, Sin = "DFS125349811", Auto = 41});
                Data.Add(new SampleDataModel()
                    {Name = "Name 5", Group = "Group 15", Hyper = 150, Sin = "YUTS12345000", Auto = null});
                Data.Add(new SampleDataModel()
                    {Name = "Name 6", Group = "Group 16", Hyper = 106, Sin = "KTRS12Y345211", Auto = null});
                Data.Add(new SampleDataModel()
                    {Name = "Name 7", Group = "Group 17", Hyper = 510, Sin = "CVS12X342895", Auto = 23});
                Data.Add(new SampleDataModel()
                    {Name = "Name 8", Group = "Group 18", Hyper = 170, Sin = "ZASS12356545", Auto = 76});
                Data.Add(new SampleDataModel()
                    {Name = "Name 9", Group = "Group 19", Hyper = 1210, Sin = "QWES18782345", Auto = 11});
                Data.Add(new SampleDataModel()
                    {Name = "Name 10", Group = "Group 21", Hyper = 1450, Sin = "RTYS989812345", Auto = 91});
                Data.Add(new SampleDataModel()
                    {Name = "Name 11", Group = "Group 31", Hyper = 1067, Sin = "SDF134562345", Auto = null});
                Data.Add(new SampleDataModel()
                    {Name = "Name 12", Group = "Group 41", Hyper = 1087, Sin = "SHGF12376745", Auto = null});
                Data.Add(new SampleDataModel()
                    {Name = "Name 13", Group = "Group 51", Hyper = 10912, Sin = "SKJU00012345", Auto = null});
            }

            public static IEnumerable<SampleDataModel> Get => Data;
        }
    public static class MaskService
        {
            public static IEnumerable<SampleDataModel> Mask(IEnumerable<SampleDataModel> data)
                {
                    List<SampleDataModel> result = new List<SampleDataModel>();

                    var result1 = (from d in data
                        select new SampleDataModel()
                        {
                            Auto = d.Auto, Group = d.Group,
                            Sin = d.Sin,
                            Hyper = (!d.Auto.HasValue) ? d.Hyper : null,
                            Name = (!d.Auto.HasValue) ? d.Name : "XXXXXX"

                        });

                    result = result1.ToList<SampleDataModel>();

                    return result;
                }
        }
    class Program
        {
            static void Main(string[] args)
            {
                var data = SampleData.Get;


                var maskedData = MaskService.Mask(data);
                foreach (var model in maskedData)
                {
                    Console.WriteLine($"{model}");
                }
             }
        }
公共类SampleDataModel
{
公共字符串名称{get;set;}
公共字符串组{get;set;}
公共整数?超{get;set;}
公共字符串Sin{get;set;}
公共int?自动{get;set;}
公共字符串注释
{
获取{return(Auto.HasValue?&Hyper&Name应该被屏蔽):“);}
}
公共重写字符串ToString()
{
返回$“Group={Group};Name={Name};Hyper={Hyper};Sin={Sin};Auto={Auto};Comment={Comment}”;
}
}
公共类抽样数据
{
私有静态只读IList数据=新列表();
静态采样数据()
{
Data.Add(新的SampleDataModel()
{Name=“Name 1”,Group=“Group 11”,Hyper=10,Sin=“S12345986554”,Auto=1});
Data.Add(新的SampleDataModel()
{Name=“Name 2”,Group=“Group 12”,Hyper=101,Sin=“ms712345231”,Auto=19});
Data.Add(新的SampleDataModel()
{Name=“Name 3”,Group=“Group 13”,Hyper=103,Sin=“SJK1234Z5666”,Auto=18});
Data.Add(新的SampleDataModel()
{Name=“Name 4”,Group=“Group 14”,Hyper=210,Sin=“DFS125349811”,Auto=41});
Data.Add(新的SampleDataModel()
{Name=“Name 5”,Group=“Group 15”,Hyper=150,Sin=“YUTS12345000”,Auto=null});
Data.Add(新的SampleDataModel()
{Name=“Name 6”,Group=“Group 16”,Hyper=106,Sin=“KTRS12Y345211”,Auto=null});
Data.Add(新的SampleDataModel()
{Name=“Name 7”,Group=“Group 17”,Hyper=510,Sin=“CVS12X342895”,Auto=23});
Data.Add(新的SampleDataModel()
{Name=“Name 8”,Group=“Group 18”,Hyper=170,Sin=“ZASS12356545”,Auto=76});
Data.Add(新的SampleDataModel()
{Name=“Name 9”,Group=“Group 19”,Hyper=1210,Sin=“QWES18782345”,Auto=11});
Data.Add(新的SampleDataModel()
{Name=“Name 10”,Group=“Group 21”,Hyper=1450,Sin=“RTYS989812345”,Auto=91});
Data.Add(新的SampleDataModel()
{Name=“Name 11”,Group=“Group 31”,Hyper=1067,Sin=“sdf13462345”,Auto=null});
Data.Add(新的SampleDataModel()
{Name=“Name 12”,Group=“Group 41”,Hyper=1087,Sin=“SHGF12376745”,Auto=null});
Data.Add(新的SampleDataModel()
{Name=“Name 13”,Group=“Group 51”,Hyper=10912,Sin=“SKJU00012345”,Auto=null});
}
公共静态IEnumerable Get=>Data;
}
公共静态类MaskService
{
公共静态IEnumerable掩码(IEnumerable数据)
{
列表结果=新列表();
var result1=(来自数据中的d
选择新的SampleDataModel()
{
自动=d.自动,组=d.组,
Sin=d.Sin,
Hyper=(!d.Auto.HasValue)?d.Hyper:null,
名称=(!d.Auto.HasValue)?d.名称:“XXXXXX”
});
result=result1.ToList();
返回结果;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
var data=SampleData.Get;
var maskedData=MaskService.Mask(数据);
foreach(maskedData中的var模型)
{
WriteLine($“{model}”);
}
}
}
只要列中有需要重写的更改,则条件或属性重写的代码都会发生更改。为了克服这个问题并重用代码,我根据stackoverflow的一些建议、google search的帖子和Microsoft的一个示例提出了通用解决方案

通用方法:

    public static class MaskService
    {
        public static bool Contains<T>(this IEnumerable<T> source, string property) where T:IMaskCriteria
        {
            if (source == null || string.IsNullOrWhiteSpace(property))
                return false;

            foreach (var maskCriteria in source)
            {
                return maskCriteria.Contains(property);
            }

            return false;
        }
        public static IEnumerable<MaskCondition> Get<T>(this IEnumerable<T> source, string property) where T : IMaskCriteria
        {
            IEnumerable<MaskCondition> result = null;
            if (source == null || string.IsNullOrWhiteSpace(property))
                return result;

            foreach (var maskCriteria in source)
            {
                if (maskCriteria.Contains(property))
                {
                    result = maskCriteria.Conditions;
                    break;
                }
            }

            return result;
        }

        public static PropertyInfo Get(this PropertyInfo[] source, string property)
        {
            if (source == null || string.IsNullOrWhiteSpace(property))
                return null;
            property = property.ToLower();
            foreach (var prop in source)
            {
                if (prop.Name.ToLower().Equals(property))
                {
                    return prop;
                }
            }

            return null;
        }
        public static IEnumerable<T> Mask<T>(this IEnumerable<T> source, IEnumerable<IMaskCriteria> maskProperties) where T : new()
        {
            var result = source.Select(MaskFun<T>(maskProperties));
            return result;
        }

        public static Func<T, T> MaskFun<T>(IEnumerable<IMaskCriteria> maskProperties) where T : new()
        {
            if (maskProperties == null)
                return null;

            Type typeofT = typeof(T);
            var model = Expression.New(typeofT);
            var inputLinqVar = Expression.Parameter(typeofT, "d");//input variable in linq query
            object GetDefault(Type type) => Nullable.GetUnderlyingType(type) != null ? null : type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : "XXXXXX";
            var maskCriterias = maskProperties as List<IMaskCriteria> ?? maskProperties.ToList();

            PropertyInfo[] props = typeofT.GetProperties();
            List<MemberAssignment> memberAssignments = new List<MemberAssignment>();
            foreach (var propertyInfo in props)
            {
                if (!propertyInfo.CanWrite)
                    continue;

                bool hasToBeMasked = maskCriterias.Contains(propertyInfo.Name);
                var valueFromLinqVariable = Expression.Property(inputLinqVar, propertyInfo); //d.{propertyName} eg. d.Id
                MemberAssignment memberAssignment = Expression.Bind(propertyInfo, valueFromLinqVariable);//{propertyName} = d.{propertyName} eg. Id = d.Id
                if (hasToBeMasked)
                {
                    List<MaskCondition> maskConditions = maskCriterias.Get(propertyInfo.Name) as List<MaskCondition>;
                    List<Expression> binConditions = new List<Expression>();
                    if (maskConditions != null)
                        foreach (var maskCondition in maskConditions)
                        {
                            var condPropInfo = props.Get(maskCondition.PropertyName);
                            Expression left = Expression.Property(inputLinqVar, condPropInfo);
                            Expression right = Expression.Constant(maskCondition.PropertyValue);
                            Expression e1 = null;
                            switch (maskCondition.Comparer)
                            {
                                case MaskConditionComparer.Equals:
                                {
                                    e1 = Expression.Equal(left, right);
                                    break;
                                }

                                case MaskConditionComparer.NotEquals:
                                {
                                    e1 = Expression.NotEqual(left, right);
                                    break;
                                }

                                case MaskConditionComparer.GreaterThan:
                                {
                                    e1 = Expression.GreaterThan(left, right);
                                    break;
                                }

                                case MaskConditionComparer.GreaterThanOrEquals:
                                {
                                    e1 = Expression.GreaterThanOrEqual(left, right);
                                    break;
                                }

                                case MaskConditionComparer.LessThan:
                                {
                                    e1 = Expression.LessThan(left, right);
                                    break;
                                }

                                case MaskConditionComparer.LessThanOrEquals:
                                {
                                    e1 = Expression.LessThanOrEqual(left, right);
                                    break;
                                }
                            }

                            binConditions.Add(e1);
                        }

                    ConstantExpression maskedValue = Expression.Constant(GetDefault(propertyInfo.PropertyType),
                        propertyInfo.PropertyType);
                    ConditionalExpression assignMaskValueIfMaskConditionTrue = null;
                    if (binConditions.Count == 1)
                    {
                        assignMaskValueIfMaskConditionTrue =
                            Expression.Condition(binConditions[0], maskedValue, valueFromLinqVariable);
                    }
                    else if (binConditions.Count > 1)
                    {
                        Expression andExpression = binConditions[0];
                        //Expression getExp(Expression e1, Expression e2) => Expression.AndAlso(e1, e2);
                        for (var i = 1; i < binConditions.Count; i++)
                        {
                            andExpression = Expression.AndAlso(andExpression, binConditions[i]);
                        }

                        assignMaskValueIfMaskConditionTrue =
                            Expression.Condition(andExpression, maskedValue, valueFromLinqVariable);
                    }
                    assignMaskValueIfMaskConditionTrue =
                    (ConditionalExpression)new ParameterReplacer(inputLinqVar).Visit(
                        assignMaskValueIfMaskConditionTrue);
                    var condExp = Expression.Lambda<Func<T, Object>>(assignMaskValueIfMaskConditionTrue, inputLinqVar);

                    memberAssignment = Expression.Bind(propertyInfo, condExp);
                }

                memberAssignments.Add(memberAssignment);
                var message = hasToBeMasked ? "will be masked" : "no masking";
                Console.WriteLine($"{propertyInfo.Name}->{propertyInfo.PropertyType.Name}==>{message};{Nullable.GetUnderlyingType(propertyInfo.PropertyType)?.FullName}");
            }

            var modelInit = Expression.MemberInit(model, memberAssignments);// new T() { propertyName = d.propertyName} eg. new Emp() { Name = d.Name }
            var lambda = Expression.Lambda<Func<T, T>>(modelInit, inputLinqVar);

            return lambda.Compile();
        }
    }
    public class ParameterReplacer : ExpressionVisitor
    {
        private readonly ParameterExpression _parameter;

        protected override Expression VisitParameter(ParameterExpression node)
        {
            return base.VisitParameter(_parameter);
        }

        public ParameterReplacer(ParameterExpression parameter)
        {
            _parameter = parameter;
        }
    }

    public class PropertyComparer : IEqualityComparer<string>
    {
        public bool Equals(string x, string y)
        {
            if (string.IsNullOrWhiteSpace(x) || string.IsNullOrWhiteSpace(y))
                return false;
            return (x.ToLower() == (y.ToLower()));
        }

        public int GetHashCode(string obj)
        {
            return obj.GetHashCode();
        }
    }

    public interface IMaskCriteria
    {
        List<string> ToBeMasked { get; set; }

        List<MaskCondition> Conditions { get; set; }

        bool Contains(string property);
    }
    public class MaskCriteria : IMaskCriteria
    {
        private  static readonly PropertyComparer comparer = new PropertyComparer();

        public MaskCriteria()
        {
            ToBeMasked = new List<string>();
            Conditions = new List<MaskCondition>();
        }
        public List<string> ToBeMasked { get; set; }

        public List<MaskCondition> Conditions { get; set; }

        public bool Contains(string property)
        {
            if (ToBeMasked == null)
                return false;

            if (string.IsNullOrWhiteSpace(property))
                return false;

            return ToBeMasked.Contains(property, comparer);
        }

    }

    public class MaskCondition
    {
        public string PropertyName { get; set; }
        public object PropertyValue { get; set; }
        public MaskConditionComparer Comparer { get; set; }
    }

    public enum MaskConditionComparer
    {
        Equals,
        NotEquals,
        GreaterThan,
        GreaterThanOrEquals,
        LessThan,
        LessThanOrEquals
    }
    class Program
    {
        static void Main(string[] args)
        {
            var data = SampleData.Get;

            Console.WriteLine("******************Start Masking Using Expression Trees In LINQ***********************");
            var mc = new MaskCriteria();
            mc.ToBeMasked.AddRange(new List<string>() { "name", "hyper" });
            mc.Conditions.Add(new MaskCondition(){ PropertyValue = null,PropertyName = "Auto", Comparer = MaskConditionComparer.Equals});

            maskedData = data.Mask<SampleDataModel>(new List<MaskCriteria>() {mc});
            foreach (var model in maskedData)
            {
                Console.WriteLine($"{model}");
            }
            Console.WriteLine("******************End Masking Using Expression Trees In LINQ***********************");
            Console.ReadLine();
        }
    }

公共静态类MaskService
{
公共静态bool包含(此IEnumerable源,字符串属性),其中T:IMaskCriteria
{
if(source==null | | string.IsNullOrWhiteSpace(属性))
返回false;
foreach(源代码中的var maskCriteria)
{
返回maskCriteria.Contains(属性);
}
返回false;
}
公共静态IEnumerable Get(此IEnumerable源,字符串属性),其中T:IMaskCriteria
{
IEnumerable结果=null;
if(source==null | | string.IsNullOrWhiteSpace(属性))
返回结果;
foreach(源代码中的var maskCriteria)
{
if(maskCriteria.Contains(属性))
{
结果=maskCriteria.条件;
打破
}
}
返回结果;
}
公共静态属性info Get(此属性info[]源,字符串属性)
{
if(source==null | | string.IsNullOrWhiteSpace(属性))
返回null;
property=property.ToLower();
foreach(源中的var prop)
{
if(prop.Name.ToLower().Equals(property))
{
返回道具;
}
}
返回null;
}
公共静态IEnumerable掩码(此IEnumerable源,IEnumerable maskProperties),其中T:new()
{
变量