C# 比较泛型结构值

C# 比较泛型结构值,c#,entity-framework,generics,C#,Entity Framework,Generics,我想比较两个通用值,为了实现这一点,我使用了如下方法: public TEntity Get(TKey key) where TKey: struct { if (!key.GetType().IsPrimitive) { throw new Exception($"Repository->Get: given type {key.GetType().Name} is not supported"); } return _dbSet.Singl

我想比较两个通用值,为了实现这一点,我使用了如下方法:

public TEntity Get(TKey key) where TKey: struct
{
    if (!key.GetType().IsPrimitive)
    {
       throw new Exception($"Repository->Get: given type {key.GetType().Name} is not supported");
    }
    return _dbSet.Single(x=> x.Id.ToString().Equals(key.ToString()));
}
如果我用

x.Id.Equals(key)
抛出异常

无法创建“System.Object”类型的常量值。只有 在此上下文中支持基元类型或枚举类型

没有使用
toString()

编辑:

在注释中获得了使用
Find
方法的答案,但这只是答案的一部分,如果我想使用
Where
方法怎么办

Edit2:

接受的答案完全解决了我的问题,只是将
struct
限制改为
IEquatable

在当前版本中,当您执行以下操作时:

_dbSet.Single(x=> x.Id.Equals(key));
由于键的类型可以是任意的,因此使用object.Equals(object)重载,因此您的
应强制转换为
对象
。EF对此有一个问题,因为它看到您使用类型为
object
的常量(如
Expression.constant
),并且您不能在SQL中使用任意类型,因此它立即表示无法将
object
常量转换为SQL

您可以通过强制您的
TKey
实现
IEquatable
来解决此问题:

IEquatable.Equals(TKey)
将使用Equals的版本,这不需要将
强制转换为
对象
。EF并不特别关心这个接口。在解析查询时,它会看到名为“Equals”的方法和兼容的签名,这就是它所关心的。因此,您也可以这样做,而不需要
IEquatable

公共静态类EfHelpers{
公共静态bool等于(TKey,TKey其他){
//不打算直接打电话
抛出新的NotImplementedException();
}
}
公共TEntity Get(TKey){
//方法具有名称“Equals”、兼容签名且不需要
//铸造对象,所以我们很好
返回_dbSet.Single(x=>EfHelpers.Equals(x.Id,key));
}

但我不建议在这种情况下这样做,因为您关心的所有类型都已经实现了
IEquatable
。但是这种技术在其他情况下可能有用。

那么x.Id的类型是什么?x.Id与key相同类型TKey您需要实现
IEquatable
,然后将其作为约束条件。你需要看看对象是否相等,而不是转换它们。@Sonikas顺便说一句,这个方法已经为你做到了。@DavidG我明白你的意思。然而,我想说的是,泛型代码与IConvertible无关。如果它与EF一起使用,那么IEquatable的实现应该能够处理这个问题。感谢您提供丰富的答案
where TKey : IEquatable<TKey>
_dbSet.Single(x=> x.Id.Equals(key));
public static class EfHelpers {
    public static bool Equals<TKey>(TKey key, TKey other) {
        // not intended to call directly
        throw new NotImplementedException();
    }
}

public TEntity Get(TKey key) {
    // method has name "Equals", compatible signature and does not require
    // casting to object, so we are fine
    return _dbSet.Single(x => EfHelpers.Equals(x.Id, key));
}