Типобезопасный эквивалент ограничения параметра типа универсального метода на незакрытый тип данного интерфейса

В С# можно ли ограничить параметр типа универсального метода таким образом, чтобы он ограничивался незакрытым типом интерфейса безопасным способом? Позвольте мне уточнить...

Например, у меня есть следующий псевдокод:

    public bool Validate<TValidator>(object validatable)
        where TValidator : IValidator<>
    {
        // code that finds all implementations of IValidator that closes on 
        // recursive base types / interfaces of the validatable object
        // return true if validates
    }

У меня есть несколько интерфейсов, реализующих IValidator, таких как ICreateValidator и IDeleteValidator. Я могу достаточно легко собрать валидаторы, которые мне нужны, в тяжелом отражении, не столь общем, как хотелось бы, таким образом, чтобы он закрывался для всех типов T и всех базовых классов T, а также интерфейсов, реализованных T.

Желание было бы в состоянии назвать что-то вроде строк

    var validates = Validate<IDeleteValidator<>>(concreteDomainObject);

Что дало бы мне незакрытый тип IDeleteValidator‹>, позволяющий мне внутренне находить каждую реализацию IDeleteValidaor, где T — либо конкретный типDomainObject, либо интерфейс, который реализует конкретный типDomainObject, либо рекурсивные базовые типы, конкретный типDomainObject расширяется до объекта. .

Конечно, я мог бы закрыть интерфейс объекта домена, просто для меня не имеет смысла вызывать

    Type unclosedValidatorType = typeof (TValidator).GetGenericTypeDefinition()

Учитывая, что я не мог быть уверен, что TValidator будет общим типом во время компиляции, и что явно закрытый TValidator не будет использоваться, кроме как для удаления его закрывающего типа, это кажется мне неправильным способом делать что-то.

Предоставленный мной псевдокод, очевидно, работает, но существует ли безопасный тип, эквивалентный типу универсального метода для незакрытого типа данного интерфейса?

отредактировано, чтобы исправить некоторые термины


person rheone    schedule 28.11.2012    source источник
comment
Вы не можете использовать where TValidator : IValidator<TValidator>?   -  person Wutz    schedule 28.11.2012
comment
@Wutz Я считаю, что то, что вы предлагаете, просто определяет объект, который закрывается сам по себе.   -  person rheone    schedule 28.11.2012
comment
Как вы хотите использовать метод и, более конкретно, как вы хотите использовать параметр типа? Почему не public bool Validate(object validatable, Type validatorType) и var validates = Validate(concreteDomainObject, typeof(IDeleteValidator<>));?   -  person phoog    schedule 28.11.2012
comment
@phoog Мое текущее решение эквивалентно предоставленной вами подписи, однако оно не настолько безопасно для типов, как мне бы хотелось, поскольку во время компиляции невозможно быть уверенным, что validatorType является универсальным типом и что его нельзя закрыть для конкретногоDomainObject .   -  person rheone    schedule 28.11.2012


Ответы (1)


В С# возможно ли ограничить тип универсального метода таким образом, чтобы он ограничивался незакрытым типом интерфейса безопасным способом?

Нет. Аргументы типа должны быть закрыты, поэтому нет смысла ограничивать параметр типа типом, который не может быть выражен как аргументы типа.

Забудьте об ограничениях для начала — этот простой код не будет работать:

using System;

class Test
{
    static void Main()
    {
        Foo<Action<>>();
    }

    static void Foo<T>()
    {
        Console.WriteLine(typeof(T));
    }
}

Ошибки:

Test.cs(7,20): error CS1525: Invalid expression term '>'
Test.cs(7,23): error CS1525: Invalid expression term ')'
Test.cs(7,24): error CS1026: ) expected
person Jon Skeet    schedule 28.11.2012
comment
Я думаю, что ОП спрашивает о формальных аргументах типа, а не о фактических аргументах типа. - person O. R. Mapper; 28.11.2012
comment
@ORMapper: Под формальными аргументами типа вы подразумеваете параметры типа? Если нет, то я не понимаю, что вы имеете в виду. Но посмотрите на пример вызова, который ОП хочет сделать: var validates = Validate<IDeleteValidaor<>>(concreteDomainObject); - person Jon Skeet; 28.11.2012
comment
Я имею в виду определения параметров типа, а не их фактические значения. Вы правы, OP также пытается фактически вызвать общий метод с открытым типом в качестве аргумента (который должен быть закрыт на основе информации, полученной из параметров метода). - person O. R. Mapper; 28.11.2012
comment
@O.R.Mapper: Верно, это разница между параметрами типа и аргументами типа, точно так же, как обычные параметры метода и аргументы метода. И я считаю, что ОП хочет передать открытые типы в качестве аргументов типа... но он не может. - person Jon Skeet; 28.11.2012
comment
@ORMapper Я исправил по почте. Извините, я использовал неправильную терминологию. Я должен был сказать, что параметр типа не просто тип - person rheone; 28.11.2012
comment
Ах, извините за путаницу - мой текст был основан на определении, которое рассматривает аргумент и параметр как синонимы с формальным и фактически является отличительным знаком. Ну, OP ожидает, что подходящая реализация интерфейса будет выбрана на основе типа объекта, переданного методу. Я не говорю, что ваш ответ был неправильным; Я просто хотел указать, что он был слишком сфокусирован на вызывающей стороне, а не на рассмотрении объявления универсального метода в первую очередь. - person O. R. Mapper; 28.11.2012
comment
@John Skeet, да, я надеялся передать открытый тип вместо того, чтобы вручную разрешать открытый тип из, возможно, произвольно закрытого типа. Что я и делаю сейчас, я просто искал более безопасный способ сделать это. - person rheone; 28.11.2012
comment
@rheone: Да, я это понимаю - я говорю, что дженерики в C # просто не поддерживают этот вариант использования. - person Jon Skeet; 28.11.2012
comment
@O.R.Mapper: Мой ответ сосредоточен на обоих — поскольку вы не можете указать открытый тип в качестве аргумента типа (как показано в примере кода), имеет смысл, что вы не можете ограничить введите parameter открытого типа. - person Jon Skeet; 28.11.2012