Преобразование типа универсальных параметров

Использование следующего кода:

Function GetSetting(Of T)(ByVal SettingName As String, ByRef DefaultVal As T) As T
    Return If(Configuration.ContainsKey(SettingName), CType(Configuration(SettingName), T), DefaultVal)
End Function

Урожаи следующая ошибка:

Value of type 'String' cannot be converted to 'T'.

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

Править: Теперь, кажется, существует три решения:

  • Используя функцию 'ValueAs', обеспеченную AMissico
  • Кастинг к 'объекту', затем к 'T', с проверкой на нулевые значения
  • Использование 'DirectCast' преобразовывает. ChangeType

Который Вы предложили бы?

Редактирование 2: это кодировало бы работу?

Function GetSetting(Of T)(ByVal SettingName As String, Optional ByRef DefaultVal As T = Nothing) As T
    Return If(Configuration.ContainsKey(SettingName), ConvertTo(Of T)(Configuration(SettingName)), DefaultVal)
End Function

Function ConvertTo(Of T)(ByVal Str As String) As T
    Return If(Str Is Nothing Or Str = "", Nothing, CType(CObj(Str), T))
End Function

Редактирование 3: [AMJ], работающий код

Function GetSetting(Of T)(ByVal SettingName As String) As T
    Return GetSetting(Of T)(SettingName, Nothing)
End Function
Function GetSetting(Of T)(ByVal SettingName As String, ByVal DefaultVal As T) As T
    Dim sValue As String = Configuration(SettingName)
    If Len(sValue) = 0 Then
        Return DefaultVal
    Else
        Return CType(CObj(sValue), T)
    End If
End Function

Быстрый метод тестирования

Public Sub DoIt()

    Me.Configuration.Add("KeyN", Nothing)
    Me.Configuration.Add("KeyE", String.Empty) '""
    Me.Configuration.Add("Key1", "99")
    Me.Configuration.Add("Key2", "1/1/2000")
    Me.Configuration.Add("Key3", "True")
    Me.Configuration.Add("Key4", "0")

    Dim o As Object 'using object in order to see what type is returned by methods

    o = Value(Of Integer)("KeyN", 10) '10
    o = Value(Of Integer)("KeyE", 10) '10
    o = Value(Of Integer)("Key1", 10) '99

    o = Value(Of Date)("KeyN", #11/11/2010#)
    o = Value(Of Date)("KeyE", #11/11/2010#)
    o = Value(Of Date)("Key2", #11/11/2010#)

    o = GetSetting(Of Integer)("KeyN", 10) '10
    o = GetSetting(Of Integer)("KeyE", 10) '10
    o = GetSetting(Of Integer)("Key1", 10) '99

    o = GetSetting(Of Date)("KeyN", #11/11/2010#)
    o = GetSetting(Of Date)("KeyE", #11/11/2010#)
    o = GetSetting(Of Date)("Key2", #11/11/2010#)

    Stop
End Sub
8
задан AMissico 24 May 2010 в 13:27
поделиться

6 ответов

Методы Value (Of T) и ValueAs поддерживают типы, допускающие значение NULL. В качестве справочника я использовал исходный код Microsoft .NET 2.0.

Это хорошо протестированный и готовый к эксплуатации код.

В этих "библиотечных" функциях нет обработки ошибок. Вызывающий объект несет ответственность за обработку любых возникающих ошибок преобразования. Единственными генерируемыми ошибками преобразования являются очевидные ошибки, такие как попытка преобразовать строку «abc» в Integer .


Public Sub DoIt()
    Dim o As Object
    o = Value(Of Integer)("foo", 10)
    o = Value(Of DateTime)("xxx", #1/1/2000#)
    o = Value(Of Boolean?)("nop", True)
    Stop
End Sub

Public Function GatherTag(ByVal tag As String) As String
    If tag = "foo" Then
        Return "99"
    Else
        Return String.Empty
    End If
End Function

''' <summary>
''' Provides strongly-typed access to the tag values. The method also supports nullable types.
''' </summary>
''' <typeparam name="T">A generic parameter that specifies the return type.</typeparam>
''' <param name="tag">The ExifTool Tag Name,</param>
''' <returns>The value, of type T, of the tag.</returns>
Public Function Value(Of T)(ByVal tag As String, ByVal defaultValue As T) As T
    Return DirectCast(ValueAs(GetType(T), tag, defaultValue), T)
End Function

''' <summary>
''' Returns the tag's value as the specified type. The method also supports nullable types.
''' </summary>
''' <param name="type">The type to return the tag value as.</param>
''' <param name="tag">The ExifTool Tag Name,</param>
''' <returns>The value of the tag as the type requested.</returns>
Public Function ValueAs(ByVal type As System.Type, ByVal tag As String, ByVal defaultValue As Object) As Object
    Dim oResult As Object = Nothing

    Dim oTag As String = GatherTag(tag)

    If Len(oTag) = 0 Then

        'use specified default value

        oResult = defaultValue

    Else

        'is requested type a generic type?

        If type.IsGenericType AndAlso type.GetGenericTypeDefinition Is GetType(Nullable(Of )) Then

            Dim oUnderlyingType As Type = Nullable.GetUnderlyingType(type)

            Dim oConstructed As Type = type.GetGenericTypeDefinition.MakeGenericType(oUnderlyingType)

            Dim oValue As Object

            oValue = System.Convert.ChangeType(oTag, oUnderlyingType)

            If oValue IsNot Nothing Then
                oResult = Activator.CreateInstance(oConstructed, oValue)
            End If

        Else

            'non-generic type

            oResult = System.Convert.ChangeType(oTag, type)

        End If

    End If

    Return oResult
End Function
4
ответ дан 5 December 2019 в 21:17
поделиться

Просто заставьте его забыть о том, что у него есть строка, предварительно применив ее к объекту.

Function GetSetting(Of T)(ByVal SettingName As String, ByRef DefaultVal As T) As T
    Return If(Configuration.ContainsKey(SettingName), CType(CObj(Configuration(SettingName)), T), DefaultVal)
End Function
2
ответ дан 5 December 2019 в 21:17
поделиться

Вам нужно наложить ограничения на определение вашего метода, чтобы ограничить его типами, которые могут быть преобразованы в строку. См. this для добавления ограничений к универсальным шаблонам. Вы можете ограничиться только одним классом. Я бы ограничился объектом (поскольку вы все равно можете указать любой тип, производный от типа ограничения), а затем вызвать ToString () вместо приведения.

0
ответ дан 5 December 2019 в 21:17
поделиться

Для этого требуется немного фокус-покуса:

Public Function GetSetting(Of T As IConvertible)(ByVal SettingName As String, ByRef DefaultVal As T) As T
    Dim formatter As IFormatProvider = CultureInfo.InvariantCulture
    Dim targetType As Type = GetType(T)

    Dim value As IConvertible = Nothing
    Return If(Configuration.TryGetValue(SettingName, value), _
        DirectCast(value.ToType(targetType, formatter), T), _
        DefaultVal)
End Function

Этот код использует отражение для вызова соответствующего метода преобразования из интерфейса IConvertible , который реализуется всеми базовыми типами значений. Результат этого преобразования можно преобразовать с помощью DirectCast .

Упрощенное: В этом коде используется метод ToType , поэтому отражение не требуется.

Обратите внимание, что ограничение типа IConvertible здесь даже не является строго необходимым - поскольку мы вызываем метод IConvertible для возвращаемого значения конфигурации String , не фактический тип. Но ограничение по-прежнему полезно, поскольку оно гарантирует, что соответствующее преобразование будет существовать.

1
ответ дан 5 December 2019 в 21:17
поделиться

Тип конфигурации a Словарь <строка, строка> (c #)?
Если да, вам не нужны дженерики.

РЕДАКТИРОВАТЬ: Если конфигурация (SettingsName) возвращает строку, контейнер не является универсальным и, следовательно, здесь вам не понадобятся универсальные шаблоны.

РЕДАКТИРОВАТЬ2:

void Main()
{
    Test<bool>.trythis("false");
    Test<bool>.trythis("true");
    Test<int>.trythis("28");
    Test<decimal>.trythis(decimal.MaxValue.ToString());
}

public class Test<T>
{
  public static void trythis(string value)
    {
        T retVal = (T)Convert.ChangeType(value, typeof(T));
        Console.WriteLine(retVal.GetType());
    }
}

Извините, я недостаточно знаю vb.net.
Это может быть Convert.ChangeType (Configuration (SettingsName), T.GetType ()) , а затем использование DirectCast поверх результатов.

Надеюсь, это поможет.

0
ответ дан 5 December 2019 в 21:17
поделиться
Public Function Value(Of T)(ByVal SettingName As String, ByVal DefaultValue As T) As T
    Return If(Configuration.ContainsKey(SettingName), DirectCast(System.Convert.ChangeType(Configuration(SettingName), GetType(T)), T), DefaultValue)
End Function
0
ответ дан 5 December 2019 в 21:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: