Как в C # есть поле, которое является массивом определенного типа (или чем-то, что его расширяет)?

#c# #.net

#c# #.net

Вопрос:

Я хочу сделать что-то вроде этого:

 public class MyAttribute : Attribute
{
    public Type<BaseAllowedType>[] handledTypes { get; set; }

    //...elided...
}
  

Тогда это позволило бы кому-то добавлять атрибут только к тем типам, которые они обрабатывают, если эти типы наследуются BaseAllowedType .

Пример:

 [MyAttribute(handledTypes = SubType)]
public class MyClass
{
}

public class SubType : BaseAllowedType
{
}
  

Возможно ли что-то подобное в C #? (Это в Java, но не уверен, что C # позволяет это)

В Java это было бы public Class<? extends BaseAllowedType>[] handledTypes

Комментарии:

1. Вы пробовали ограничения универсального типа ? Может быть, что-то вроде public class MyClass<T> where T : BaseAllowedType

2. @LewsTherin C # не допускает общих атрибутов, так что это не вариант.

3. @DanielMann Я думаю, это зависит от того, действительно ли OP нуждается в том, чтобы это было атрибутом, или это проблема XY .

4. Я не понимаю, почему это отклонено; это вполне разумный вопрос.

5. Я отмечаю, что вы ссылаетесь конкретно на массивы . К вашему сведению, C # имеет тот же недостаток дизайна, что и Java, в том, что ковариация небезопасного массива является законной. То есть, если у вас есть a Giraffe[] , вы можете присвоить его Animal[] переменной, которая затем ужасно вылетит при попытке вставить a Turtle в массив.

Ответ №1:

Во-первых, это свойство, а не поле.

Во-вторых, свойства не могут быть обобщены в C #, как и атрибуты. (И ни один из них не может быть полями, если на то пошло. Только классы, структуры, интерфейсы, делегаты и методы могут быть обобщены.)

Тем не менее, мы можем ответить на ваш вопрос.

Существует два способа установить ограничение на параметр универсального типа. Первый — наложить ограничение на объявление универсального класса или метода:

 class Foo<T> where T : Animal {}
  

Теперь Foo<Giraffe> или Foo<Animal> или Foo<Turtle> являются законными, но Foo<string> это не так.

Во-вторых, в интерфейсах и делегатах вы можете поместить аннотацию ковариации:

 interface IFoo<out T> 
{
  T SomeProperty { get; }
}
  

Но T должно использоваться только в выходных позициях. С помощью этого ограничения вы можете присвоить IFoo<Giraffe> переменной типа IFoo<Animal> , но не наоборот.

Между этими двумя функциями обычно можно создать разумное ограничение типа в C #.

Комментарии:

1. Спасибо за помощь. Я не уверен, что любой из них достигает того, чего я хочу. Я полагаю, что ваше первое означает, что Foo это не может быть атрибутом (который мне нужен для основного класса), а ваш второй ожидает object тип T , но мне не нужен объект, мне нужна ссылка на тип (например typeof(MyType) )

2. @DonRhummy: О, если вы хотите, чтобы это были объекты типа runtime, вам не повезло. Средство проверки типов во время компиляции C # не передает информацию о типе среды выполнения , поскольку средство проверки типов во время компиляции выполняется до времени выполнения.

3. @DonRhummy: если вам нужен массив Type объектов, в котором Type объекты представляют типы, обладающие определенным свойством, просто проверьте это свойство во время выполнения и выдайте исключение, если задан тип, который не соответствует вашему требованию.

4. хорошо, это то, что я сделаю. Я надеялся, что он был встроен в язык, как в Java. Спасибо! Я буду использовать Contract.Requires<ArgumentException>(...)