2015-05-28 3 views
1

У меня есть базовый класс DtaRow, который имеет внутренний массив строк, содержащих данные. У меня есть десятки подклассов DtaRow, таких как UnitRow и AccountRow, но единственная цель - предоставить свойства для получения значений, поэтому вы можете сделать aUnit.Name вместо aUnit.pFields(3).Понимание Array.ConvertAll, могу ли я DirectCast?

У меня также есть объект DtaTable, который содержит Friend pRows As New Dictionary(Of Integer, DtaRow). Обычно я не вставляю DtaRows в DtaTable, я вставляю подклассы, такие как UnitRows и AccountRows. Любая таблица имеет только один тип.

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

Public Readonly Property Units() As IEnumerable 
    Get 
     Return Tables(5).pRows.Values 'oh oh oh oh table 5, table 5... 
    End Get 
End Property 

Это, очевидно, возвращает список DtaRows, не UnitRows, что означает, что я не могу сделать MyDB.Units(5).Name, что является конечной Цель.

Очевидное решение - Dim ret As New UnitRow() и DirectCast все в это, но тогда я постоянно строю тысячи новых массивов. Uggg. В качестве альтернативы я могу повесить DirectCast везде, где я вытаскиваю значение, а также uggg.

Я вижу, что есть метод Array.ConvertAll, который выглядит так, как будто это может быть то, что я хочу. Но, может быть, это просто делает цикл для меня и ничего не спасает? И если это то, что я хочу, я действительно не понимаю, как использовать DirectCast в нем.

Надеюсь, я просто пропустил какой-то другой бит API, который делает то, что я хочу, но в противном случае, какое лучшее решение здесь? Я подозреваю, что мне нужно ...

  • сделать расширение конверсии в каждом подклассе DtaRow?
  • или что-то в DtaTable, что делает то же самое?
+0

Другое решение? Кажется, что настоящая проблема заключается в том, что я объявил контейнер контейнером (Словарь (Integer, DtaRow)). Это должно быть ** не ** сказать DtaRow? Он должен сказать , правильно? –

ответ

1

Вы можете использовать ConvertAll для преобразования массива в другой тип.

Dim arr(2) As A 
    Dim arr2() As B 

    arr(0) = New B 
    arr(1) = New B 
    arr(2) = New B 

    arr2 = Array.ConvertAll(arr, Function(o) DirectCast(o, B)) 

Class A 

End Class 

Class B 
    Inherits A 

End Class 

В вашем случае, я думаю, что это будет выглядеть следующим образом

Return Array.ConvertAll(Tables(5).pRows.Values, Function(o) DirectCast(o, UnitRow)) 

Обратите внимание, что это создаст новый массив каждый раз.

+0

Это действительно работало - это часть 'Function (o)', которую я не получал. Но если это каждый раз создает новый массив, это не будет ** хорошим ** решением. Возможно, есть совершенно другой способ приблизиться к этому? –

+0

Я беру это обратно. Ошибка Значение типа 'System.Collections.Generic.Dictionary (Of Integer, SFImporterDLL.DtaRow) .ValueCollection' не может быть преобразовано в '1-мерный массив SFImporterDLL.DtaRow' Несколько попыток решить эту проблему потерпели неудачу. Я недостаточно понимаю эту концепцию, чтобы продолжить. –

1

Вы можете отличить объекты от list(Of String) на основе нужного вам поля.

Return Tables(5).pRows.Values.Cast(Of DtaRow).Select(Function(r) r.name).ToList 
+0

(править) Uhhhh, я не уверен, что это решает проблему. Цель состоит в том, что MyDB.Units (5) .Name', и если я возвращаю общий список строк, я теряю это. Или я чего-то не хватает? –

+0

Не уверен, что вы после. Думал, что вам нужна коллекция имен. – OneFineDay

+0

Все вещи 'Lambda' или' LINQ' используют внутренний цикл - не могут уйти от этого. Большинство из нас, как читаемость запроса/выражения. – OneFineDay

0

ДА! Я пошел нелинейно. Это работает только из-за OOP ...

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

Так что подождите ... метод, который извлекает строку из коллекции, составляет в классе коллекции, а не в различных подклассах DtaRow. Итак, вот что я сделал ...

Public ReadOnly Property Units() As IEnumerable 
    Get 
     Return Tables(dbTblUnits).pRow.Values 
    End Get 
End Property 
Public ReadOnly Property Units(ByVal K as Integer) As UnitRow 
    Get 
     Return DirectCast(Tables(dbTblUnits)(K), UnitRow) 
    End Get 
End Property 
Public ReadOnly Property Units(ByVal K as String) As UnitRow 
    Get 
     Return DirectCast(Tables(dbTblUnits).Rows(K), UnitRow) 
    End Get 
End Property 

Почему это решает проблему? Хорошо нормально, если кто-то ...

Dim U as UnitRow = MyDB.Units(K) 

Было бы назвать первый метод (который все, что я был первоначально), который будет возвращать .Values ​​из словаря, а затем по умолчанию Свойство будет называться вернуть .item (K). Но из-за того, как работает диспетчер методов, если я предоставляю более конкретную версию, которая более точно соответствует параметрам, она будет называть это. Поэтому я предоставляю переопределения, которые являются одноранговыми подклассами, которые выполняют литье.

Теперь это не идеально, потому что, если я просто позвоню, чтобы получить весь список, когда я вытаскиваю из него строки, мне все равно придется их бросать. Но люди ожидают, поэтому это вполне приемлемо в этом случае. Еще лучше, когда я открываю эту DLL в VBA, видна только первая из этих методов, которая возвращает всю коллекцию, а это означает, что Units (k) вызовет свойство Default на DtaTable, возвращая DtaRow, но это нормально в VBA.

ООП на помощь!

Смежные вопросы