приведение к универсальному типу во время выполнения - PullRequest
0 голосов
/ 10 сентября 2010

Хорошо, я не думаю, что это возможно, поэтому я подумал, что я бы попросил убедиться. Я нахожусь в процессе создания функции, которая отражает свойства в классе и добавляет их к имеющейся у меня структуре данных. Некоторые из свойств являются общими типами.

Допустим, у нас есть DataType(Of T) со свойством .Value типа T:

Dim properties = GetType(MyType).GetFields(Reflection.BindingFlags.Public Or _
                                           Reflection.BindingFlags.Instance)
For Each prop As fieldinfo In properties
   Collection.Add(prop.Name,prop.GetValue(poco))
Next

В collection.Add для примитивных типов (Integer, String и т. Д. & Hellip;) я просто хочу добавить тип ... но в случае универсальных я хочу добавить DataType(Of T).Value. Я надеюсь, что есть обходной путь, но я не думаю, что есть выход, потому что тип T не может быть определен во время компиляции, верно? В идеале DirectCast(prop.getvalue(poco), DataType(Of T)).Value было бы возможно. Это когда вы надеялись, что появится даже больше динамики, чем в .NET 4.0.

Ответы [ 2 ]

1 голос
/ 11 сентября 2010

Мне только что пришло в голову, что я, возможно, неправильно прочитал ваш вопрос. Поэтому другой ответ от меня.

Вы можете избежать необходимости приводить к универсальному типу (где вы не знаете параметр типа) во время выполнения, вводя новый интерфейс, который позволяет получить доступ к некоторому свойству Value:

Public Interface IHasValue
    Public ReadOnly Property Value As Object
End Interface

Далее убедитесь, что ваш класс DataType(Of T) реализует этот интерфейс. Это означает, что каждый DataType(Of T) объект (независимо от того, какой конкретный тип T) является также IHasValue, и вы сможете проверить это с помощью TypeOf(…) Is IHasValue:

Public Class DataType(Of T) : Implements IHasValue

    Public Value As T

    Public ReadOnly Property UntypedValue As Object Implements IHasValue.Value
        Get
            Return Me.Value
        End Get
    End Property

End Class

(Такое дублирование Value необходимо по двум причинам: во-первых, когда DataType(Of T).Value является полем вместо свойства, а во-вторых, потому что они не имеют одинаковый тип.)

Затем, заполняя свою коллекцию полями, вы можете проверить, является ли конкретное поле DataType(Of T) (и, если это так, развернуть из него Value), выполнив следующее:

Dim value As Object = prop.GetValue(poco)

If TypeOf(value) Is IHasValue Then         ' <- is value a DataType(Of T) ?    '
    value = CType(value, IHasValue).Value  ' <- if so, unwrap the value        '
End If

Collection.Add(prop.Name, value)

Это, вероятно, больше того, что вы ищете, чем мой другой ответ, но позвольте мне подчеркнуть это:

If TypeOf(…) Is … Then … - это кодовый запах . Возможно, вам следует переосмыслить свой код и исследовать решения, связанные с полиморфизмом.

0 голосов
/ 11 сентября 2010

Во-первых, мои предположения о том, что вы пытаетесь сделать:

  1. У вас есть объект с именем poco, имеющий тип MyType.

  2. MyType имеет поля разных типов, поэтому вы думаете, что вам нужны дженерики.

  3. У вас есть коллекция пар ключ-значение с именем Collection, возможно, с типом Dictionary(Of String, Object)?

  4. Вы хотите перенести все поля poco (т.е. их имена и значения) в Collection.


Боковой узел: Вы смешиваете поля со свойствами: ваш код работает с полями (вызывая GetFields), аВаш текст вопроса говорит о свойствах.Это не одно и то же!


Во-вторых, некоторые фундаментальные факты о коллекциях и системе статических типов:

  • Нетипизированные коллекции (где элементы имеют тип Object) могут хранить все виды значений в нем.

  • Типизированные коллекции (где элементы имеют более конкретный тип, напримерT) может хранить только значения, имеющие тип T или тип, полученный из T.


В-третьих, выводы, сделанные на основании вышеизложенного:

  • В вашем случае Collection должен быть нетипизированной коллекцией, если действительно верно, что poco (имеющий тип MyType) имеет поля различных типов.

  • В этом случае дженерики вообще не помогут, потому что дженерики не для этого.Обобщения полезны, когда вы хотите определить операции (т. Е. Методы, поведение), которые работают одинаково независимо от типа объекта, над которым они работают.

    Например, List(Of T) определяет тип коллекции, который работает одинаково, независимо от типа T.Но это не означает, что вы можете поместить что-либо в List(Of T), потому что как только вы создадите экземпляр этого типа - например, с помощью Dim xs As New List(Of String) -, T будет зафиксирован для определенного типа - String -, и выв итоге получим типизированную коллекцию, которая принимает значения только этого типа.

    Итак, еще раз: если вам нужна коллекция, в которой хранятся различные типы объектов, выберите Object в качестве типа значения вместо попытки найтирешение с использованием дженериков.


При этом существует другое решение: полиморфизм .

Если вы хотите, чтобы ваш код обрабатывал значенияиначе, в зависимости от их типа, полиморфизм - это путь:

  • Сначала вы определяете интерфейс или абстрактный базовый класс (например, DataType, хотя я настоятельно рекомендую вамвыберите более понятное имя!), которое указывает, что можно сделать с вашими значениями.

  • Во-вторых, введите Collection как Dictionary(Of String, DataType).Это означает, что в коллекцию могут входить только объекты типа DataType или что-либо производное от него.

  • В-третьих, наследовать от / Implement DataType, чтобы указать поведение для определенного типа.

Есть интересное слайд-шоу под названием Условные обозначения и полиморфизм , которые могут быть здесь интересны.


Примечание: И последнее, но не менее важное: вы можете выяснить тип параметра универсального типа: TypeOf(T).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...