不能同时指定约束类和'class'或& # 39;结构# 39;约束

本文关键字:约束 结构 class 不能 | 更新日期: 2023-09-27 17:54:42

我试图通过创建IDbSet的自定义模拟来解决模拟问题。

自定义模拟:

public class DbSetMock : IDbSet<Tenant>
{
    /* hidden all other implemented methods/properties */
    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, Tenant
    {
        throw new NotImplementedException();
    }
}

create方法给出了一个构建错误,我不知道如何解决:

不能同时指定约束类和'class'或'struct'约束

简单地从约束中删除class会导致另一个构建错误(我也不理解)。

方法'Tests.DAL.Tenants.DbSetMock.Create()'的类型参数'TDerivedEntity'的约束必须匹配接口方法'System.Data.Entity.IDbSet. create()'的类型参数'TDerivedEntity'的约束。考虑使用显式接口实现。

谁能帮我成功地建立这个类?

不能同时指定约束类和'class'或& # 39;结构# 39;约束

由于TDerived类型参数被约束为Tenant,因此添加classstruct约束是多余的。只需删除class约束。

UPDATE:奇怪的是,这里似乎有编译器错误之间的冲突。如果你"修复"了一个,你就会得到另一个,陷入绝望的无限循环。幸运的是,第二个错误也为我们提供了一个解决方法:您可以使用显式接口实现:

public class DbSetMock : IDbSet<Tenant>
{
    TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
    {
        throw new NotImplementedException();
    }
}
如果不使用显式接口实现, 似乎无法实现方法。如果您需要它作为类的公共接口的一部分,我建议创建接口实现转发的另一个方法:
public class DbSetMock : IDbSet<Tenant>
{
    TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
    {
        return Create<TDerivedEntity>();
    }
    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
    {
        throw new NotImplementedException();
    }
}

尝试从方法部分删除class,像这样;

public class DbSetMock : IDbSet<Tenant>
    {
        /* hidden all other implemented methods/properties */
        public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
        {
            throw new NotImplementedException();
        }
    }

class, Tenant是冗余代码。

目前框架中只有三个可继承的类,其后代可能是值类型:Object, ValueTypeEnum。所有这三种类型都是类类型,但是从ValueTypeEnum派生的任何类型都是值类型,从Object派生的任何不是从ValueType派生的类型都是类类型。对于上述以外的任何类型,classstruct约束要么是冗余的,要么是矛盾的;不巧的是,c#不允许为上述类型直接指定约束。

在一些语言和框架中,一种流行的设计哲学是,如果存在一种特定的表达形式,那么适用于该一般形式的行为将是无用的,那么语言/框架设计者就没有理由特意禁止这种形式。在这样的理念下,将泛型类型约束为密封类型(例如Fnord))是完全合法的。如果所讨论的类型是密封的,并且没有未来的版本将永远是,那么这样的事情将是毫无意义的,但是由于将通用约束的正常解释应用于这种情况将产生合理的行为,并且由于可以想象在某些情况下此类约束可能是有用的(例如编写代码使用正在开发中的类,目前是密封的,但可能会或可能不会在其最终版本中被密封),或者编写代码与基于反射的代码接口,这些代码需要特定的泛型形式),其哲学将建议将泛型类型约束为密封类应该是合法的。

在其他一些语言和框架中,有不同的哲学:如果程序员可能期望某种特定形式的结构提供超出一般形式的功能,但它没有,如果这种特殊形式没有这些功能似乎不是很有用,语言应该禁止它,即使该结构具有定义良好的精确含义,并且不能通过其他方式表达,如果语言的实现者看不到程序员想要表达实际含义的理由。

c#和。net都没有将一个类型参数约束为另一个类型参数的问题,即使另一个参数的类型不被接受为约束,这表明由于上述哲学,该语言人为地施加了限制。在我看来,这是很不幸的,因为在很多情况下,如果能够说,例如:

bool HasAnyFlags<T>(this T enum1, T enum2) where T:struct,System.Enum

,即使。net将有用地允许这样的结构,即使唯一的障碍,阻止c#例外的代码显式地寻找这样的约束,以禁止他们,c#设计师决定禁止这样的结构,而不是允许他们的行为,因为。net将解释他们(意味着HasAnyFlags不能做任何事情直接与T,它不能做System.Enum。使用T作为System.Enum通常不会比使用System.Enum更快(有时更慢),但T仍然可能有用,原因如下:

  1. 该方法可以在编译时强制参数必须为"相同"枚举类型
  2. 该方法可以使用静态类' EnumEvaluator '来生成和缓存' Func '类型的静态委托,这样' HasAnyFlags(T enum1, T enum2) '可以实现为' return EnumEvaluator.HasAnyFlags(enum1,enum2); '。这样的函数可能比' enum_hasflag '快十倍以上。

尽管如此,指定这样的约束可能很有用,但在c#中指定它们的唯一方法是让c#源代码指定一些可以用作约束的虚拟类型,然后通过一个实用程序运行编译后的代码,该实用程序将用对首先想要使用的类型的引用替换对虚拟类型的所有引用。

它告诉你的是约束:

class, Tenant

是多余的。您可以删除class,因为Tenantclass更受约束,并且包括class