C# 有没有一种方法可以重复使用LINQ语句,但改变对该属性调用的属性和方法?
我有下面的代码片段,我似乎不能想出一个优雅的方法来重构它,所以我没有违反复制/粘贴编程。请注意这个片段并不完整,但我相信它应该有必要的信息来提供适当的上下文。任何帮助都将不胜感激C# 有没有一种方法可以重复使用LINQ语句,但改变对该属性调用的属性和方法?,c#,linq,C#,Linq,我有下面的代码片段,我似乎不能想出一个优雅的方法来重构它,所以我没有违反复制/粘贴编程。请注意这个片段并不完整,但我相信它应该有必要的信息来提供适当的上下文。任何帮助都将不胜感激 public static void Main() { IEnumerable<Person> dataSet = new List<Person> { new Person{ ID = "1", PrimaryName = "Prim", SecondaryNa
public static void Main()
{
IEnumerable<Person> dataSet = new List<Person>
{
new Person{ ID = "1", PrimaryName = "Prim", SecondaryName = "Sec"},
new Person{ ID = "2", PrimaryName = "test", SecondaryName = "Sec2"},
new Person{ ID = "3", PrimaryName = "test", SecondaryName = "Sec3"}
};
string attribute = "LastName";
OperatorValue queryOperator = OperatorValue.Equal;
string value = "test";
switch (attribute)
{
case ("LastName"):
if (queryOperator.Equals(OperatorValue.Equal))
{
dataSet = dataSet.Where(p => p.PrimaryName.Equals(value));
}
else if (queryOperator.Equals(OperatorValue.NotEquals))
{
dataSet = dataSet.Where(p => !p.PrimaryName.Equals(value));
}
else if (queryOperator.Equals(OperatorValue.StartsWith))
{
dataSet = dataSet.Where(p => p.PrimaryName.StartsWith(value));
}
else
{
dataSet = dataSet.Where(p => p.PrimaryName.Contains(value));
}
break;
case ("FirstName"):
if (queryOperator.Equals(OperatorValue.Equal))
{
dataSet = dataSet.Where(p => p.SecondaryName.Equals(value));
}
else if (queryOperator.Equals(OperatorValue.NotEquals))
{
dataSet = dataSet.Where(p => !p.SecondaryName.Equals(value));
}
else if (queryOperator.Equals(OperatorValue.StartsWith))
{
dataSet = dataSet.Where(p => p.SecondaryName.StartsWith(value));
}
else
{
dataSet = dataSet.Where(p => p.SecondaryName.Contains(value));
}
break;
case ("ID"):
if (queryOperator.Equals(OperatorValue.Equal))
{
dataSet = dataSet.Where(p => p.ID.Equals(value));
}
else if (queryOperator.Equals(OperatorValue.NotEquals))
{
dataSet = dataSet.Where(p => !p.ID.Equals(value));
}
else if (queryOperator.Equals(OperatorValue.StartsWith))
{
dataSet = dataSet.Where(p => p.ID.StartsWith(value));
}
else
{
dataSet = dataSet.Where(p => p.ID.Contains(value));
}
break;
}
foreach (Person person in dataSet)
Console.WriteLine(person.ID);
}
public enum OperatorValue
{
Equal,
NotEquals,
StartsWith
}
public class Person
{
public string ID { get; set; }
public string SecondaryName { get; set; }
public string PrimaryName { get; set; }
}
publicstaticvoidmain()
{
IEnumerable数据集=新列表
{
新人{ID=“1”,PrimaryName=“Prim”,SecondaryName=“Sec”},
新人{ID=“2”,PrimaryName=“test”,SecondaryName=“Sec2”},
新人{ID=“3”,PrimaryName=“test”,SecondaryName=“Sec3”}
};
字符串属性=“LastName”;
运算符值查询运算符=运算符值等于;
字符串值=“测试”;
开关(属性)
{
案例(“姓氏”):
if(queryOperator.Equals(OperatorValue.Equal))
{
dataSet=dataSet.Where(p=>p.PrimaryName.Equals(value));
}
else if(queryOperator.Equals(OperatorValue.NotEquals))
{
dataSet=dataSet.Where(p=>!p.PrimaryName.Equals(value));
}
else if(queryOperator.Equals(OperatorValue.StartsWith))
{
dataSet=dataSet.Where(p=>p.PrimaryName.StartsWith(value));
}
其他的
{
dataSet=dataSet.Where(p=>p.PrimaryName.Contains(value));
}
打破
案例(“名字”):
if(queryOperator.Equals(OperatorValue.Equal))
{
dataSet=dataSet.Where(p=>p.SecondaryName.Equals(value));
}
else if(queryOperator.Equals(OperatorValue.NotEquals))
{
dataSet=dataSet.Where(p=>!p.SecondaryName.Equals(value));
}
else if(queryOperator.Equals(OperatorValue.StartsWith))
{
dataSet=dataSet.Where(p=>p.SecondaryName.StartsWith(value));
}
其他的
{
dataSet=dataSet.Where(p=>p.SecondaryName.Contains(value));
}
打破
案件编号:
if(queryOperator.Equals(OperatorValue.Equal))
{
数据集=数据集,其中(p=>p.ID.Equals(value));
}
else if(queryOperator.Equals(OperatorValue.NotEquals))
{
数据集=数据集。其中(p=>!p.ID.Equals(value));
}
else if(queryOperator.Equals(OperatorValue.StartsWith))
{
dataSet=dataSet.Where(p=>p.ID.StartsWith(value));
}
其他的
{
dataSet=dataSet.Where(p=>p.ID.Contains(value));
}
打破
}
foreach(数据集中的人员)
Console.WriteLine(person.ID);
}
公共枚举运算符值
{
平等,
NotEquals,
开始
}
公共阶层人士
{
公共字符串ID{get;set;}
公共字符串SecondaryName{get;set;}
公共字符串PrimaryName{get;set;}
}
在switch语句中有更多的情况,我想用同样的方法来处理,所以你可以看到这开始变得很糟糕。我试图想出一个助手方法,我可以为每个案例调用它,但我完全被卡住了,没有主意。谢谢你的帮助 如果要使代码可重用,而不必每次都复制/粘贴,则需要按新属性进行筛选。您可以执行以下操作:
public static void Main()
{
IEnumerable<Person> dataSet = new List<Person>
{
new Person{ ID = "1", PrimaryName = "Prim", SecondaryName = "Sec"},
new Person{ ID = "2", PrimaryName = "test", SecondaryName = "Sec2"},
new Person{ ID = "3", PrimaryName = "test", SecondaryName = "Sec3"}
};
string attribute = "LastName";
OperatorValue queryOperator = OperatorValue.Equal;
string value = "test";
Func<Person, string> getter = GetFuncForProperty(attribute);
dataSet = Filter(dataSet, getter, queryOperator, value);
foreach (Person person in dataSet)
Console.WriteLine(person.ID);
}
public static IEnumerable<Person> Filter(IEnumerable<Person> source, Func<Person, string> getter, OperatorValue operatorValue, string searchValue)
{
switch (operatorValue)
{
case OperatorValue.Equal:
return source.Where(p => getter.Invoke(p).Equals(searchValue));
case OperatorValue.NotEquals:
return source.Where(p => !getter.Invoke(p).Equals(searchValue));
case OperatorValue.StartsWith:
return source.Where(p => getter.Invoke(p).StartsWith(searchValue));
}
throw new ArgumentException(operatorValue.ToString() + " is not supported");
}
public static Func<Person, string> GetFuncForProperty(string propertyName)
{
switch (propertyName)
{
case "ID":
return (Person person) => person.ID;
case "FirstName":
return (Person person) => person.SecondaryName;
case "LastName":
return (Person person) => person.PrimaryName;
}
throw new ArgumentException(propertyName + " is not supported");
}
public enum OperatorValue
{
Equal,
NotEquals,
StartsWith
}
public class Person
{
public string ID { get; set; }
public string SecondaryName { get; set; }
public string PrimaryName { get; set; }
}
publicstaticvoidmain()
{
IEnumerable数据集=新列表
{
新人{ID=“1”,PrimaryName=“Prim”,SecondaryName=“Sec”},
新人{ID=“2”,PrimaryName=“test”,SecondaryName=“Sec2”},
新人{ID=“3”,PrimaryName=“test”,SecondaryName=“Sec3”}
};
字符串属性=“LastName”;
运算符值查询运算符=运算符值等于;
字符串值=“测试”;
Func getter=GetFuncForProperty(属性);
dataSet=过滤器(dataSet、getter、queryOperator、value);
foreach(数据集中的人员)
Console.WriteLine(person.ID);
}
公共静态IEnumerable筛选器(IEnumerable源、Func getter、运算符值、运算符值、字符串搜索值)
{
开关(运算符值)
{
大小写运算符值。等于:
返回source.Where(p=>getter.Invoke(p).Equals(searchValue));
案例运算符value.NotEquals:
返回source.Where(p=>!getter.Invoke(p).Equals(searchValue));
case operator value.StartsWith:
返回source.Where(p=>getter.Invoke(p).StartsWith(searchValue));
}
抛出新ArgumentException(不支持operatorValue.ToString()+);
}
公共静态Func GetFuncForProperty(字符串propertyName)
{
交换机(propertyName)
{
案例“ID”:
返回(Person)=>Person.ID;
案例“名字”:
return(Person)=>Person.SecondaryName;
案例“LastName”:
return(Person)=>Person.PrimaryName;
}
抛出新ArgumentException(不支持propertyName+);
}
公共枚举运算符值
{
平等,
NotEquals,
开始
}
公共阶层人士
{
公共字符串ID{get;set;}
公共字符串SecondaryName{get;set;}
公共字符串PrimaryName{get;set;}
}
如果您想使代码可重用,并且不必每次需要按新属性进行筛选时都复制/粘贴代码,请查看它在以下位置运行:。您可以执行以下操作:
public static void Main()
{
IEnumerable<Person> dataSet = new List<Person>
{
new Person{ ID = "1", PrimaryName = "Prim", SecondaryName = "Sec"},
new Person{ ID = "2", PrimaryName = "test", SecondaryName = "Sec2"},
new Person{ ID = "3", PrimaryName = "test", SecondaryName = "Sec3"}
};
string attribute = "LastName";
OperatorValue queryOperator = OperatorValue.Equal;
string value = "test";
Func<Person, string> getter = GetFuncForProperty(attribute);
dataSet = Filter(dataSet, getter, queryOperator, value);
foreach (Person person in dataSet)
Console.WriteLine(person.ID);
}
public static IEnumerable<Person> Filter(IEnumerable<Person> source, Func<Person, string> getter, OperatorValue operatorValue, string searchValue)
{
switch (operatorValue)
{
case OperatorValue.Equal:
return source.Where(p => getter.Invoke(p).Equals(searchValue));
case OperatorValue.NotEquals:
return source.Where(p => !getter.Invoke(p).Equals(searchValue));
case OperatorValue.StartsWith:
return source.Where(p => getter.Invoke(p).StartsWith(searchValue));
}
throw new ArgumentException(operatorValue.ToString() + " is not supported");
}
public static Func<Person, string> GetFuncForProperty(string propertyName)
{
switch (propertyName)
{
case "ID":
return (Person person) => person.ID;
case "FirstName":
return (Person person) => person.SecondaryName;
case "LastName":
return (Person person) => person.PrimaryName;
}
throw new ArgumentException(propertyName + " is not supported");
}
public enum OperatorValue
{
Equal,
NotEquals,
StartsWith
}
public class Person
{
public string ID { get; set; }
public string SecondaryName { get; set; }
public string PrimaryName { get; set; }
}
publicstaticvoidmain()
{
IEnumerable数据集=新列表
{
新人{ID=“1”,PrimaryName=“Prim”,SecondaryName=“Sec”},
新人{ID=“2”,PrimaryName=“test”,SecondaryName=“Sec2”},
新人{ID=“3”,PrimaryName=“test”,SecondaryName=“Sec3”}
};
字符串属性=“LastName”;
操作工
public static OperatorValue ToOperatorValue(this string queryOperator)
{
// TODO: exception if input null
return Enum.Parse(typeof(OperatorValue), queryOperator);
// TODO: decide what to do if queryOperator has not existing enum value
}
string queryOperatorTxt = ...
OperatorValue operator = queryOperatorTxt.ToOperatorValue();
public static Expression<Func<Person, string>> ToPropertySelector(this string attributeTxt)
{
// TODO: check incorrect parameters
Expression<Func<Person, string>> propertySelector;
switch (attributeTxt)
{
case "LastName":
propertySelector = (person) => person.PrimaryName;
break;
case "FirstName":
propertySelector = (person) => person.SecondaryName;
break;
... etc
default:
// TODO: decide what to do with unknown attributeTxt
}
}
string attributeTxt = ...
Expression<Func<Person, string>> propertySelector = attributeTxt.ToPropertySelector();
public static IQueryable<Person> Where(
this IQueryable<Person> source,
Expression<Func<Person, string>> propertySelector,
OperatorValue operator,
string value)
{
// TODO: exceptions if incorrect parameters
switch (operator)
{
case OperatorValue.Equals:
return source.Where(item => propertySelector(item) == value);
case OperatorValue.NotEquals:
return source.Where(item => propertySelector(item) != value);
case OperatorValue.StartsWith:
return source.Where(item => propertySelector(item).StartsWith(value);
case OperatorValue.Contains:
return source.Where(item => propertySelector(item).Contains(value);
default:
// TODO
}
}
IQueryable<Person> dataSet = db.Persons;
string attributeTxt = ...
string queryOperatorTxt = ...
string value = ...
Expression<Func<Person, string>> propertySelector = attributeTxt.ToPropertySelector();
OperatorValue operation = queryOperatorTxt.ToOperatorValue();
IQueryable<Person> queryPersons = dataSet.Where(propertySelector, operation);