I am trying to work around a mocking issue by creating a custom mock of IDbSet.
The custom mock:
public class DbSetMock : IDbSet<Tenant>
{
/* hidden all other implemented methods/properties */
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, Tenant
{
throw new NotImplementedException();
}
}
The create method gives a build error that I have no clue on how to solve:
cannot specify both a constraint class and the 'class' or 'struct' constraint
Simply removing class
from the constraints results in another build error (which I also don't understand :( ).
The constraints for type parameter 'TDerivedEntity' of method 'Tests.DAL.Tenants.DbSetMock.Create<TDerivedEntity>()' must match the constraints for type parameter 'TDerivedEntity' of interface method 'System.Data.Entity.IDbSet<BusinessLayer.DAL.Tenants.Tenant>.Create<TDerivedEntity>()'. Consider using an explicit interface implementation instead.
Can anybody help me successfully building this class?
Since the TDerived
type parameter is constrained to be a Tenant
, adding the constraints class
or struct
is redundant. Just remove the class
constraint.
UPDATE: Curiously there seems to be a conflict between the compiler errors here. If you "fix" one you get the other, in an infinite loop of despair. Luckily, the second error also gives us a way out: you can use an explicit interface implementation:
public class DbSetMock : IDbSet<Tenant>
{
TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
{
throw new NotImplementedException();
}
}
There seems to be no way to implement that method without using explicit interface implementation. If you need it as part of the public interface of the class, I suggest creating another method that the interface implementation forwards to:
public class DbSetMock : IDbSet<Tenant>
{
TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
{
return Create<TDerivedEntity>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
{
throw new NotImplementedException();
}
}
Try to remove class
from method part, like this;
public class DbSetMock : IDbSet<Tenant>
{
/* hidden all other implemented methods/properties */
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
{
throw new NotImplementedException();
}
}
class, Tenant
is redundant code.
There are presently only three inheritable classes in the Framework whose descendants may be value types: Object
, ValueType
, and Enum
. All three of those types are class types, but any type derived from ValueType
or Enum
will be a value type, and any type derived from Object
which is not derived from ValueType
will be a class type. With any type other than the above, a class
or struct
constraint would either be redundant or contradictory; not coincidentally, C# disallows constraints to be directly specified for the above types.
In some languages and frameworks, a prevailing design philosophy is that if there is a particular form of expression where the behavior that applies to that general form would be useless, there's no reason for the language/framework designer to go out of the way to forbid such a form. Under such a philosophy, it would be perfectly legal to have a generic type constrained to a sealed type (e.g. Fnord)
. Such a thing would be pointless if the type in question were sealed and no future version would ever be otherwise, but since applying the normal interpretation of generic constraints to such situation would yield reasonable behavior, and since there might conceivably be some situations where such constraints might be useful (e.g. writing code to use a class which is in development and is presently sealed, but may or may not be sealed in its final release, or writing code to interface with Reflection-based code that expects particular generic forms), the philosophy would suggest that constraining a generic type to a sealed class should be legal.
In some other languages and frameworks, a differing philosophy holds: if a programmer might expect some particular form of a construct to offer features beyond the general form but it does not, and if that particular form wouldn't seem very useful without such features, the language should forbid it, even if the construct would have a precise meaning which was well-defined and could not be expressed via other means if the implementers of the language don't see a reason for programmers to want to express that actual meaning.
The fact that neither C# nor .net has any problem with having one type parameter constrained to another, even when that other parameter is of a type that would not be accepted as a constraint, suggests that the restriction is artificially imposed by the language due to the aforementioned philosophy. It's unfortunate, IMHO, since there are many situations where it would be helpful to be able to say, e.g.
bool HasAnyFlags<T>(this T enum1, T enum2) where T:struct,System.Enum
and even though .net would usefully allow such a construct, and even though the only obstacle which prevents C# from excepting it code to explicitly looks for such constraints so as to disallow them, the C# designers decided to forbid such constructs rather than allow them to behave as .net would interpret them (meaning that HasAnyFlags
couldn't do anything directly with a T
that it couldn't do with System.Enum
, and using a T
as a System.Enum
would generally be no faster than using a System.Enum
(sometimes slower), but T
could nonetheless be useful for a couple reasons:
Still, useful as it might be to specify such constraints, the only way to specify them in C# is to have the C# source code specify some dummy type which could be used as a constraint, and then run the compiled code through a utility which will replace all references to the dummy type with references to the type one wanted to use in the first place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With