Невозможно указать как класс ограничений, так и ограничение "class" или " struct

Я пытаюсь работать вокруг глумливый вопрос путем создания пользовательского макета 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" тестов метода.ДАЛМАТИНЕЦ.Арендаторы.DbSetMock.Create () 'должен соответствовать ограничениям для параметра типа "TDerivedEntity" системы метода интерфейса.Данные.Сущность.IDbSet Create()'. Вместо этого рассмотрите возможность использования явной реализации интерфейса.

может ли кто-нибудь помочь мне успешно построить этот класс?

4 ответов


С TDerived параметр типа ограничен Tenant, добавив ограничения class или struct избыточна. Просто удалите class ограничения.

обновление: Любопытно, что здесь существует конфликт между ошибками компилятора. Если вы "исправите" одно, вы получите другое, в бесконечном цикле отчаяния. К счастью, вторая ошибка, также дает нам выход: вы можете использовать явную реализацию интерфейса:

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, ValueType и Enum. Все три этих типа являются типами классов, но любой тип, производный от ValueType или Enum будет тип значения, и любой тип, производный от Object, который не является производным от ValueType будет типом класса. С любым типом, отличным от вышеуказанного, a class или struct ограничение было бы избыточным или противоречивым; не случайно, 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. метод может обеспечить во время компиляции, что параметры должны быть перечисленным типом *same*
  2. метод может использовать статический класс ' EnumEvaluator` для генерации и статические делегаты кэша типа "Func", такие, что "HasAnyFlags(T enum1, T enum2)" могут быть реализованы как " возвращаемый EnumEvaluator.HasAnyFlags(enum1,enum2);`. Такая функция может быть более чем в десять раз быстрее, как перечисление.HasFlag`.

тем не менее, как бы полезно было указать такие ограничения, единственный способ указать их в C# - это указать исходный код C# на некоторый фиктивный тип, который может использоваться в качестве ограничения, а затем запустить скомпилированный код через утилиту, которая заменит все ссылки на фиктивный тип ссылками на тип, который нужно использовать в первую очередь.


Он говорит вам, что ограничений:

class, Tenant

избыточна. Вы можете просто удалить class С Tenant более ограничен, чем class и включает в себя class.