Невозможно указать как класс ограничения, так и ограничение класса или структуры
Я пытаюсь обойти насмешливую проблему, создав собственный макет 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
из результатов ограничений приводит к другой ошибке сборки (что я также не понимаю:().
Ограничения для параметра типа "TDerivedEntity" метода "Tests.DAL.Tenants.DbSetMock.Create <TDerivedEntity> ()" должны соответствовать ограничениям для параметра типа "TDerivedEntity" метода интерфейса "System.Data.Entity.IDbSet < BusinessLayer.DAL.Tenants.Tenant > .Create <TDerivedEntity> ()". Вместо этого рассмотрите использование явной реализации интерфейса.
Может кто-нибудь помочь мне успешно построить этот класс?
Ответы
Ответ 1
Поскольку параметр типа 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();
}
}
Ответ 2
Попробуйте удалить class
из части метода, например:
public class DbSetMock : IDbSet<Tenant>
{
/* hidden all other implemented methods/properties */
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
{
throw new NotImplementedException();
}
}
class, Tenant
является избыточным кодом.
Ответ 3
В структуре в настоящее время есть только три наследуемых класса, потомками которых могут быть типы значений: Object
, ValueType
и Enum
. Все три типа являются типами классов, но любой тип, полученный из ValueType
или Enum
, будет типом значения, и любой тип, полученный из Object
, который не является производным от ValueType
, будет типом класса. При любом типе, отличном от указанного выше, ограничение class
или struct
будет либо избыточным, либо противоречивым; не случайно, С# запрещает прямые ограничения для указанных типов.
В некоторых языках и структурах преобладающая философия дизайна заключается в том, что если существует определенная форма выражения, в которой поведение, применимое к этой общей форме, было бы бесполезным, нет никаких оснований для того, чтобы разработчик языка/структуры не мог выйти из способ запретить такую форму. В соответствии с такой философией было бы совершенно законно иметь общий тип, ограниченный закрытым типом (например, Fnord)
. Такая вещь была бы бессмысленной, если бы рассматриваемый тип был запечатан, и никакой будущей версии не было бы иначе, но поскольку применение обычной интерпретации общих ограничений к такой ситуации привело бы к разумному поведению, и поскольку, возможно, могут быть некоторые ситуации, когда такие ограничения могут быть полезными (например, писать код для использования класса, который находится в разработке и в настоящее время запечатан, но может или может не запечатываться в его окончательном выпуске или писать код для взаимодействия с кодом на основе Reflection, который ожидает конкретные общие формы), философия предполагает, что ограничение типичного типа на закрытом классе должно быть законным.
В некоторых других языках и структурах существует другая философия: если программист может ожидать, что какая-то конкретная форма конструкции предложит функции за пределами общей формы, но это не так, и если эта конкретная форма не будет казаться очень полезной без такие функции, язык должен запрещать его, даже если конструкция будет иметь точный смысл, который был бы четко определен и не мог бы быть выражен другими средствами, если разработчики языка не видят причины, по которым программисты хотят выразить это фактическое значение.
Тот факт, что ни С#, ни .net не имеет проблемы с тем, что один параметр типа привязан к другому, даже если этот другой параметр относится к типу, который не принимается в качестве ограничения, предполагает, что ограничение искусственно навязывается языка из-за вышеупомянутой философии. Это печально, ИМХО, поскольку есть много ситуаций, когда было бы полезно иметь возможность сказать, например.
bool HasAnyFlags<T>(this T enum1, T enum2) where T:struct,System.Enum
и хотя .net с пользой допускает такую конструкцию, и хотя единственное препятствие, которое препятствует тому, чтобы С# исключало его код, чтобы явно искать такие ограничения, чтобы запретить их, дизайнеры С# решили запретить такие конструкции, а не позволяют им вести себя так, как .net будет их интерпретировать (это означает, что HasAnyFlags
не может ничего сделать непосредственно с T
, который он не мог бы сделать с System.Enum
, а использование T
как System.Enum
как правило, не быстрее, чем при использовании System.Enum
(иногда медленнее), но T
может, тем не менее, быть полезным по нескольким причинам:
- В момент компиляции метод может принудительно установить, что параметры должны быть * одинаковыми * перечисляемыми типами
- Метод может использовать статический класс `EnumEvaluator` для создания и кэширования статических делегатов типа` Func`, так что `HasAnyFlags (T enum1, T enum2)` может быть реализован как `return EnumEvaluator.HasAnyFlags(enum1, enum2 ); `. Такая функция может быть более чем в десять раз быстрее, чем `Enum.HasFlag`.
Тем не менее, полезно, поскольку это может указывать на такие ограничения, единственный способ указать их в С# состоит в том, чтобы исходный код С# указывал некоторый фиктивный тип, который можно было бы использовать в качестве ограничения, а затем запустить скомпилированный код через которая заменит все ссылки на фиктивный тип ссылками на тип, который хотел бы использовать в первую очередь.
Ответ 4
Это говорит о том, что ограничение:
class, Tenant
является избыточным. Вы можете просто удалить class
, поскольку Tenant
больше ограничений, чем class
и включает class
.