Главная » C# » Присваивание состояния при неизвестном типе в Visual C# (Sharp)

0

При работе с обобщениями .NET одна из наиболее распространенных проблем порождается необходимостью работать с собственными  типами  (proper  types). Так, в реализации интерфейса iworksheet необходимо реализовать метод AssignCellState (), определенный В интерфейсе IWorksheetSerialize.

Но здесь имеется проблема, состоящая в том, что функция передается как параметр определенного тип и присваивается переменной CellState, которая является дрим неопределенным обобщением .NET. Метод AssignCellstateO реализуется следующим образом:

public void AssignCellState(int row, int col, object value) { CellState[row, col] = (BaseType)value;

Код выглядит очень простым и невинным, но в действительности скрывает много возможных проблем. Здесь значение параметра value является типа object. Потом для его преобразования в тип BaseType — т. к. CellState определен этим типом — выполняется операция приведения типов. В большинстве случаев, если значение правильного типа, этот код будет работать.

Но следующий код сгенерирует исключение: IWorksheet<double> worksheet = new Worksheet<double>(); worksheet.Dimension(10, 10);

string buffer = "hello worlds-

worksheet. AssignCellState (1, 2, buffer);

Переменная worksheet объявлена типом double. При вызове метода AssignCellstateO ячейке (1,2 ) присваивается  тип string. Вызов метода AssignCellState о не представляет проблем, но в его реализации операция прваивания будет неуспешной, т. к. мы не можем просто так присвоить тип string типу double. Это, конечно же, порождает вопрос, зачем  вообще  нужна функция типа object? Потому, что иногда у нас просто нет другого выхода и нужно создать метод общего объекта. Правильным способом вызова метода будет следующий:

IWorksheet<double> worksheet = new Worksheet<double>(); worksheet.Dimension(10, 10);

string buffer = "hello world"; worksheet.AssignCellState(l, 2, Double.Parse(buffer));

Выделенный жирным шрифтом код показывает, что значение типа string преобруется с помощью метода Double.Parse() в значение типа double. Это преобразание, конечно же, будет неудачным, т. к. буфер не является строковым предстаением числа, но это уже другая проблема.

Другим способом решить эту проблему будет вообще не поднимать данного вопра, и объявить метод обобщением .NET. Преимущество обобщений .NET заключтся в том, что они позволяют типовую безопасность исполнения, не заставляя явно пользователя реализовывать процедуры преобразования. Рассмотрим следующее объявление метода AssignCeiistate()  с применением обобщений .NET:

public void AssignCellState<ValueType>(int row, int col, ValueType value) { if  (typeof(BaseType).IsAssignableFrom(typeof(ValueType)))  {

CellState[row, col] = (BaseType)(object)value;

}

else if (value is string &&

typeof(double).IsAssignableFrom(typeof(BaseType)))  { CellState[row, col] =

(BaseType)(object)double.Parse((string)(object)value);

}

else {

throw new InvalidCastException("Could not perform conversion");

}

}

Состояние,  которое  нужно  присвоить  ячейке,  является  параметром  обобщения

.NET, чей  тип  определен  как ValueType. Мы можем только предполагать, каким является конкретный тип ValueType; определение типа делается, когда вызывается метод AssignCellstateo (). Допустим, что вызывается следующий метод:

string buffer = "hello world"; worksheet.AssignCellState(l, 2, buffer);

В данном случае тип ValueType будет string, хотя мы это явно и не указывали. Одной из возможностей, предоставляемых методами обобщений .NET, является неявное определение типов. В следующем коде метод AssignCellstateo () иользуется явным образом.

string buffer = "hello world"; worksheet.AssignCellState<string>(1, 2, buffer);

Зная, что ValueType имеет тип string, метод сначала выполнит проверку, можно

ЛИ ValueType присваиват ь  BaseType:

if (typeof(BaseType).IsAssignableFrom(typeof(ValueType))) {

Код довольно хитроумный, т. к. для определения возможности присваивания одного  типа  другому  в  нем  используется  отражение  (reflection).  По  существу,

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

CellState[row, col] = (BaseType)(object)value;

Здесь мы сначала преобразуем тип в object, после чего выполняем преобразование в BaseType, который как раз и является типом, которым был объявлен лист. Оперия приведение к типу object является обязательной, т. к. в противном случае компилятор С# выдаст ошибку о невозможности выполнения приведения.

Но допустим, что тип нельзя присвоить непосредственно. Скажем, что переменная value ссылается на строковое представление числа. В таком случае можно с помь ю Отражения Проверить, КаКИМИ ТИПаМИ ЯВЛЯЮТСЯ ValueType И BaseType, и вы – полнить преобразование самостоятельно:

else if (value is string &&

typeof(double).IsAssignableFrom(typeof(BaseType)))

В первой части оператора if выполняется проверка, является ли value переменной С ТИПОМ String, а во второй выполняется Проверка, МОЖН О ЛИ BaseType присвоить double. Положительный результат обеих проверок означает, что вводимые данные относятся к типу string, а тип листа — double; соответственно, для преобразовия нужно лишь вызвать метод Double. Parse ().

Функциональность автоматического преобразования не уменьшает необходимый объем кода, но централизует его и делает его общего назначения. Вызывающему коду обычно не нужно будет заботиться о выполнении наиболее распространенных преобразований, т. к. они будут выполняться автоматически. Конечно же, предпагется, что эти наиболее распространенные преобразования реализованы прраммистом. Для тех же преобразований, которые нельзя выполнить, вбрасывается исключение приведения, точно так же, как это сделал бы и первоначальный метод AssignCeilstate ()  на основе объекта.

В общем, метод AssignCeilstateo () с параметрами обобщения  .NET предостаяет возможность аккуратно присвоить значение листу и аккуратный и сопровоаемый метод для выполнения преобразования. Таким образом, удовлетворяется первоначальное требование иметь возможность безопасного смешения типов.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

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