Typification of general parameters

Using the following code:

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 

Sets the following error:

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

In any case, I could point out that in all cases the conversion will actually be possible (I basically get integers, Booleans, doubles and strings).

Edit : now there seem to be three solutions:

  • Using the "ValueAs" Feature Provided by AMissico
  • Casting to `object`, then` T`, checking for null values
  • Using `DirectCast` over Convert.ChangeType

What would you suggest?

Edit 2: Will this code work?

 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 

Edit 3: [AMJ] Work Code

 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 

Quick test method

 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
generics casting
source share
7 answers

The Value(Of T) and ValueAs support ValueAs types. I used the source code of Microsoft.NET 2.0 as a reference.

This is a well-tested and ready-made production code.

There is no error handling in these "library" functions. The responder must handle any conversion errors that occur. The only conversion errors generated are obvious errors, such as trying to convert the string "abc" to 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 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
source share

This requires a bit of focus focus:

 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 

This code uses reflection to invoke the appropriate conversion method from the IConvertible interface, which is implemented by all basic value types. The result of this conversion can be used with DirectCast .

Simplified: This code uses the ToType method, so it does not require reflection.

Note that restricting the type of IConvertible here is not even absolutely necessary - since we call the IConvertible method the return value of the String configuration, not the actual type. But the restriction is still useful, as it ensures that the corresponding transformation will exist.

+1
source share

Just, just make it forget that it has a string by first dropping it onto the object.

 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 
+1
source share

You need to put restrictions on the definition of a method in order to limit it to types that can be passed to a string. See this for adding restrictions for generics. You can limit yourself to just one class. I would hold back the object (because you can still specify t aas any type derived from the contraint type), and then call ToString () instead of Toing instead of Calling.

0
source share

Is type Configuration a Dictionary<string, string> (C #)?
If so, you do not need generics.

EDIT: if Configuration(SettingsName) returns a string, the container is not generic and therefore you do not need generics here.

EDIT2:

 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()); } } 

I'm sorry, I do not know enough vb.net. It could be Convert.ChangeType(Configuration(SettingsName), T.GetType()) , and then use DirectCast based on the results.

Hope this helps.

0
source share
 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
source share

I know it’s too late to answer this question, but I was looking for something similar and found out that there is another way to do this.

Using the IConvertible interface and requiring T generic type to implement the interface. So, we can use the Convert.ChangeType() method.

The code is pretty easy to write, then

 Function GetSetting(Of T As IConvertible)(ByVal SettingName As String, _ Optional ByRef DefaultVal As T = Nothing) _ As T If Configuration.ContainsKey(SettingName) Then Return Convert.ChangeType(Configuration(SettingName), GetType(T)) End If Return DefaultVal End Function 
0
source share

All Articles