是否可以在 C# 中创建具有自定义值或模板值的谓词
Is it possible to create in C# a predicate with a custom values, or templated values
我是 C# 的新手,有 C++ 背景。我一直在寻找列表搜索和 Find
.
的用法
我正在尝试定义一个接受参数的函数,returns 是列表中的一个条目。例如
class Product
{
public string id;
public string description;
}
public List<Product> products = new List<Product>();
// Add some items to the list
我的问题是,我可以使用 Predicates/Funcs
等 C# 功能来打开以下自定义“查找”功能吗
Product GetProductByID(string id)
{
foreach (Product p in products)
{
if (p.id == id)
{
return p;
}
}
}
我尝试过使用谓词,但我似乎无法找到将值输入函数以进行布尔表达式检查的方法。我了解如何编写谓词来查找列表中的特定项,但不是可以传入的动态项。
理想情况下,我想更进一步并对其进行模板化,以便 Predicate 可用于任何具有相似结构的项目列表。
即如果我们也有
class Employee
{
public string id;
public int age;
}
public List<Employee> employees = new List<Employee>();
// Add some items to the list
使用相同定义的谓词真的很酷,但是在这个完全不同类型的列表上。即类似
// psudo
Predicate<T, string> predicate = return <T>.id == id;
它之所以有效,是因为 T 总是具有一个名为 id
的字符串成员的类型
我希望一切都有意义。
I understand how I would write a Predicate to find a speciic item in a list, but not a dynamic one that could be passed in.
这就是 lambda 表达式的用武之地,它允许您创建一个委托类型的实例来捕获范围内的变量。例如:
public Predicate<Product> CreateProductPredicateForId(string id)
{
return product => product.id == id;
}
现在要使 通用 ,您需要有一个指定 Id
属性 的接口。然后你可以写一个泛型方法。例如:
public interface IEntity
{
string Id { get; }
}
...
public Predicate<T> CreatePredicateForId<T>(string id) where T : IEntity
{
return entity => entity.Id == id;
}
(注意:在整个过程中我都在使用 Func<T, bool>
- 但完全相同的逻辑适用于 Predicate<T>
- 它们具有相同的签名,但你往往会看到更多的前者而不是这些天是后者;也就是说:List<T>
使用后者)
泛型支持这一点,但通过变体规则;您必须声明以下形式的接口:
interface IHazId
{
int Id { get; }
}
class Foo : IHazId // your types need to implement it, too!
{
public int Id { get; set; }
}
然后就可以通用使用了:
void SomeCallingCode()
{
// get the predicate, however
int id = 42;
Func<IHazId, bool> predicate = obj => obj.Id == id;
// use it
SomeTypeSpecificMethod(predicate);
}
void SomeTypeSpecificMethod(Func<Foo, bool> predicate)
=> throw new NotImplementedException("not shown");
与 compiler/runtime 允许 Func<IFoo, bool>
满足特定类型的 Func<Foo, bool>
要求,因为它知道所有 Foo
都是 IHazId
。您还可以使用具有约束的泛型来执行此操作:
void SomeCallingCode()
{
// get the predicate, however
int id = 42;
Func<IHazId, bool> predicate = obj => obj.Id == id;
// use it
SomeGenericMethod<Foo>(predicate);
}
void SomeGenericMethod<T>(Func<T, bool> predicate)
where T : IHazId
=> throw new NotImplementedException("not shown");
然而,实际上,这很少有用,因为在大多数情况下您已经知道类型,并且只想做:
int id = 42;
SomeTypeSpecificMethod(x => x.Id == id);
另请注意,允许您将 Func<IHazId, bool>
视为 Func<SomeType, bool>
的差异规则仅适用于 reference type SomeType
- 这是说:class
,而不是 struct
.
您可以使用 LINQ
Product myProduct = products.Where(p => p.Id == id).FirstOrDefault();
您需要在文件顶部 using System.Linq;
才能使用它。
Product GetProductByID(string id)
{
foreach (Product p in products)
{
if (p.id == id)
{
return p;
}
}
}
这可以替换为
products.FirstOrDefault(p => p.Id == id)
你问题的第二部分可以通过继承轻松解决,比如
public class ProductA
{
public string Id { get; set; }
}
public class ProductB : ProductA
{
}
List<ProductA> a = new List<ProductA>();
List<ProductB> b = new List<ProductB>();
Func<ProductA, bool> findFunction = (p) => p.Id == id;
var p = a.FirstOrDefault(findFunction);
p = b.FirstOrDefault(findFunction);
我是 C# 的新手,有 C++ 背景。我一直在寻找列表搜索和 Find
.
我正在尝试定义一个接受参数的函数,returns 是列表中的一个条目。例如
class Product
{
public string id;
public string description;
}
public List<Product> products = new List<Product>();
// Add some items to the list
我的问题是,我可以使用 Predicates/Funcs
等 C# 功能来打开以下自定义“查找”功能吗Product GetProductByID(string id)
{
foreach (Product p in products)
{
if (p.id == id)
{
return p;
}
}
}
我尝试过使用谓词,但我似乎无法找到将值输入函数以进行布尔表达式检查的方法。我了解如何编写谓词来查找列表中的特定项,但不是可以传入的动态项。
理想情况下,我想更进一步并对其进行模板化,以便 Predicate 可用于任何具有相似结构的项目列表。
即如果我们也有
class Employee
{
public string id;
public int age;
}
public List<Employee> employees = new List<Employee>();
// Add some items to the list
使用相同定义的谓词真的很酷,但是在这个完全不同类型的列表上。即类似
// psudo
Predicate<T, string> predicate = return <T>.id == id;
它之所以有效,是因为 T 总是具有一个名为 id
我希望一切都有意义。
I understand how I would write a Predicate to find a speciic item in a list, but not a dynamic one that could be passed in.
这就是 lambda 表达式的用武之地,它允许您创建一个委托类型的实例来捕获范围内的变量。例如:
public Predicate<Product> CreateProductPredicateForId(string id)
{
return product => product.id == id;
}
现在要使 通用 ,您需要有一个指定 Id
属性 的接口。然后你可以写一个泛型方法。例如:
public interface IEntity
{
string Id { get; }
}
...
public Predicate<T> CreatePredicateForId<T>(string id) where T : IEntity
{
return entity => entity.Id == id;
}
(注意:在整个过程中我都在使用 Func<T, bool>
- 但完全相同的逻辑适用于 Predicate<T>
- 它们具有相同的签名,但你往往会看到更多的前者而不是这些天是后者;也就是说:List<T>
使用后者)
泛型支持这一点,但通过变体规则;您必须声明以下形式的接口:
interface IHazId
{
int Id { get; }
}
class Foo : IHazId // your types need to implement it, too!
{
public int Id { get; set; }
}
然后就可以通用使用了:
void SomeCallingCode() { // get the predicate, however int id = 42; Func<IHazId, bool> predicate = obj => obj.Id == id; // use it SomeTypeSpecificMethod(predicate); } void SomeTypeSpecificMethod(Func<Foo, bool> predicate) => throw new NotImplementedException("not shown");
与 compiler/runtime 允许 Func<IFoo, bool>
满足特定类型的 Func<Foo, bool>
要求,因为它知道所有 Foo
都是 IHazId
。您还可以使用具有约束的泛型来执行此操作:
void SomeCallingCode() { // get the predicate, however int id = 42; Func<IHazId, bool> predicate = obj => obj.Id == id; // use it SomeGenericMethod<Foo>(predicate); } void SomeGenericMethod<T>(Func<T, bool> predicate) where T : IHazId => throw new NotImplementedException("not shown");
然而,实际上,这很少有用,因为在大多数情况下您已经知道类型,并且只想做:
int id = 42; SomeTypeSpecificMethod(x => x.Id == id);
另请注意,允许您将 Func<IHazId, bool>
视为 Func<SomeType, bool>
的差异规则仅适用于 reference type SomeType
- 这是说:class
,而不是 struct
.
您可以使用 LINQ
Product myProduct = products.Where(p => p.Id == id).FirstOrDefault();
您需要在文件顶部 using System.Linq;
才能使用它。
Product GetProductByID(string id)
{
foreach (Product p in products)
{
if (p.id == id)
{
return p;
}
}
}
这可以替换为
products.FirstOrDefault(p => p.Id == id)
你问题的第二部分可以通过继承轻松解决,比如
public class ProductA
{
public string Id { get; set; }
}
public class ProductB : ProductA
{
}
List<ProductA> a = new List<ProductA>();
List<ProductB> b = new List<ProductB>();
Func<ProductA, bool> findFunction = (p) => p.Id == id;
var p = a.FirstOrDefault(findFunction);
p = b.FirstOrDefault(findFunction);