Проблема ковариации массивов реального мира

#c# #c#-4.0 #covariance #contravariance

#c# #c #-4.0 #ковариация #контравариантность

Вопрос:

Я пытаюсь создать массив класса DataTableColumn, но, к сожалению, я схожу с ума от этого. К настоящему времени это то, что я пытался сделать без какого-либо успеха

 public interface IDataTableColumn<out TValue> {
    string Expression { get; }
    DataTableFilterType FilterType { get; }

    TValue Cast(string value);
}

public class DataTableColumn<TValue> : IDataTableColumn<TValue> {
    public DataTableColumn(string expression, DataTableFilterType filterType = DataTableFilterType.Equal) {
        Expression = expression;
        FilterType = filterType;
    }

    public string Expression { get; private set; }
    public DataTableFilterType FilterType { get; private set; }

    public TValue Cast(string value) {
        return value.As<TValue>();
    }
}
  

Мой массив ДОЛЖЕН быть похож

 private readonly IDataTableColumn<object>[] _columns = {
    new DataTableColumn<int>("Id"), // ERROR
    new DataTableColumn<string>("Description", DataTableFilterType.StartsWith), // SUCCESS
    new DataTableColumn<DateTime?>("Date"), // ERROR
};
  

На самом деле работает так

 private readonly dynamic[] _columns = {
    new DataTableColumn<int>("Id"),
    new DataTableColumn<string>("Description", DataTableFilterType.StartsWith),
    new DataTableColumn<DateTime?>("Date"),
};
  

Я думаю, что использование dynamic — не лучший способ сделать это .. кто-нибудь, пролейте свет, пожалуйста!

Редактировать

черт, я забыл об ошибке

Не удается неявно преобразовать тип DataTableColumn< int >’ в ‘IDataTableColumn< object >’. Существует явное преобразование (вы пропускаете приведение?)

Не удается неявно преобразовать тип DataTableColumn< System.Дата-время? >’ в ‘IDataTableColumn< объект >’. Существует явное преобразование (вы пропускаете приведение?)

Ответ №1:

Я полагаю, это потому, что int и DateTime являются типами значений, которые не являются ковариантными с object (они требуют упаковки). При компиляции вашего кода я получаю следующую ошибку:

 covar.cs(23,13): error CS0266: Cannot implicitly convert type
    'DataTableColumn<System.DateTime>' to 'IDataTableColumn<object>'.
    An explicit conversion exists (are you missing a cast?)
  

Согласно MSDN, «Различия в универсальных интерфейсах (C # и Visual Basic)»:

Различия в универсальных интерфейсах поддерживаются только для ссылочных типов. Типы значений не поддерживают дисперсию. Например, IEnumerable<int> ( IEnumerable(Of Integer) в Visual Basic) не может быть неявно преобразовано в IEnumerable<object> ( IEnumerable(Of Object) в Visual Basic), потому что целые числа представлены типом значения.

DataTableColumn<string> работает, потому что он является прямым производным от object .

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

1. Но нет способа сделать что-то подобное? нет подхода?

2. @Kim, обычно ответ заключается в том, чтобы иметь IFoo<T> производную от IFoo , а затем пусть ваш массив будет типа IFoo . Ковариация работает для ссылочных типов , вот почему вы видите свою ошибку.

3. Хорошо, все, я просто пытаюсь здесь найти «ответ» на мою проблему, а не причину проблемы. В любом случае спасибо.

4. @Kim: Ну, ответ в том, что ваша стратегия вряд ли будет осуществимой. Предложение @Anthony является распространенным подходом.

5. Я воспользуюсь предложением @Anthony’s. Спасибо за вас обоих.