我正在尝试通过创建IDbSet的自定义模拟来解决mocking issue。
自定义模拟:
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&lt; TDerivedEntity&gt;()'的类型参数'TDerivedEntity'的约束必须与接口方法'System.Data.Entity.IDbSet&lt;的类型参数'TDerivedEntity'的约束匹配; BusinessLayer.DAL.Tenants.Tenant&GT; .Create&LT; TDerivedEntity&GT;()”。请考虑使用显式接口实现。
有人能帮助我成功建立这个课程吗?
答案 0 :(得分:13)
由于TDerived
类型参数被限制为Tenant
,因此添加约束class
或struct
是多余的。只需删除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();
}
}
答案 1 :(得分:3)
尝试从方法部分删除class
,就像这样;
public class DbSetMock : IDbSet<Tenant>
{
/* hidden all other implemented methods/properties */
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
{
throw new NotImplementedException();
}
}
class, Tenant
是冗余代码。
答案 2 :(得分:2)
目前,Framework中只有三个可继承的类,其后代可能是值类型:Object
,ValueType
和Enum
。所有这三种类型都是类类型,但从ValueType
或Enum
派生的任何类型都是值类型,以及从Object
派生的任何类型都不是从{{1}派生的将是一个类类型。对于上述以外的任何类型,ValueType
或class
约束将是多余的或相互矛盾的;不巧的是,C#不允许直接为上述类型指定约束。
在某些语言和框架中,流行的设计哲学是,如果存在一种特定的表达形式,其中适用于该一般形式的行为将毫无用处,那么语言/框架设计师就没有理由一路走开,禁止这样的形式。在这样的哲学下,将通用类型约束为密封类型(例如struct
)是完全合法的。如果所涉及的类型被密封且没有将来的版本,这样的事情将毫无意义。否则,但由于将通用约束的正常解释应用于这种情况会产生合理的行为,并且因为可能存在这样的约束可能有用的一些情况(例如编写代码以使用正在开发的类并且目前是密封的,但可能会或可能不会被封存在其最终版本中,或者编写代码以与基于反射的代码(需要特定的通用形式)接口,哲学会建议将通用类型约束到密封类应该是合法的
在其他一些语言和框架中,不同的哲学认为:如果程序员可能期望某种特定形式的构造提供超出一般形式的特征,但它不会,并且如果该特定形式看起来不是很在没有这些特征的情况下有用,语言应该禁止它,即使构造具有明确定义的精确含义,并且如果语言的实现者没有看到程序员的理由,则无法通过其他方式表达想表达那个实际意义。
C#和.net都没有任何问题,即将一个类型参数约束到另一个类型参数,即使其他参数属于不被接受为约束的类型,也表明该限制是由人为强加的。语言由于上述哲学。不幸的是,恕我直言,因为有很多情况可以说,例如。
Fnord)
尽管.net可以有用地允许这样的构造,即使阻止C#除了代码以明确地寻找这些约束以便禁止它们的唯一障碍,C#设计者决定禁止这样的构造而不是允许他们表现为.net会解释它们(意味着bool HasAnyFlags<T>(this T enum1, T enum2) where T:struct,System.Enum
无法直接使用HasAnyFlags
做T
,而System.Enum
无法使用T
作为System.Enum
的{{1}}通常不会比使用System.Enum
(有时更慢)更快,但T
可能会因某些原因而有用:
仍然很有用,因为它可能是指定这样的约束,在C#中指定它们的唯一方法是让C#源代码指定一些可以用作约束的虚拟类型,然后通过实用程序将替换对虚拟类型的所有引用,并引用首先要使用的类型。
答案 3 :(得分:1)
它告诉你的是约束:
class, Tenant
是多余的。您可以删除class
,因为Tenant
比class
更受限制,并且包含class
。