Help with a Generic function
-
I set out to write a Generic function that would find controls of a desired type and pass back an array of that type. For instance I could call the function and ask for all textbox's found on a form. However, I ran into a snag. I can test if a control is of Type T, but I have know way of converting that control to Type T. The following code shows the compromise I had to make due to this limitation.
'Returns a control array full of controls that match the desired type Public Function ControlArray(Of T)(ByVal container As Control) As Control() 'Controls to pass back Dim list As New List(Of Control) For Each ctrl As Control In container.Controls 'If child control is of the desired type T then 'add to list If ctrl.GetType Is GetType(T) Then list.Add(ctrl) Next 'Return array Return list.ToArray End Function
Ideally this function would look something like the code below. The big difference is I want to return an array of type T. But how can I possibly convert a generic control to an unknown type?
Public Function ControlArray(Of T)(ByVal container As Control) As T() 'Controls to pass back Dim list As New List(Of T) For Each ctrl As Control In container.Controls 'If child control is of the desired type T then 'add to list If ctrl.GetType Is GetType(T) Then 'The next statement won't compile and is the major problem I 'need to work around list.Add(DirectCast(ctrl, T)) End If Next 'Return array Return list.ToArray End Function
-
I set out to write a Generic function that would find controls of a desired type and pass back an array of that type. For instance I could call the function and ask for all textbox's found on a form. However, I ran into a snag. I can test if a control is of Type T, but I have know way of converting that control to Type T. The following code shows the compromise I had to make due to this limitation.
'Returns a control array full of controls that match the desired type Public Function ControlArray(Of T)(ByVal container As Control) As Control() 'Controls to pass back Dim list As New List(Of Control) For Each ctrl As Control In container.Controls 'If child control is of the desired type T then 'add to list If ctrl.GetType Is GetType(T) Then list.Add(ctrl) Next 'Return array Return list.ToArray End Function
Ideally this function would look something like the code below. The big difference is I want to return an array of type T. But how can I possibly convert a generic control to an unknown type?
Public Function ControlArray(Of T)(ByVal container As Control) As T() 'Controls to pass back Dim list As New List(Of T) For Each ctrl As Control In container.Controls 'If child control is of the desired type T then 'add to list If ctrl.GetType Is GetType(T) Then 'The next statement won't compile and is the major problem I 'need to work around list.Add(DirectCast(ctrl, T)) End If Next 'Return array Return list.ToArray End Function
You need to constrain your generic statement. In C#, you'd do it like this public List<T> ControArray<T>(Control container) where T : Control Not sure of the VB syntax.
Christian Graus - C++ MVP 'Why don't we jump on a fad that hasn't already been widely discredited ?' - Dilbert
-
You need to constrain your generic statement. In C#, you'd do it like this public List<T> ControArray<T>(Control container) where T : Control Not sure of the VB syntax.
Christian Graus - C++ MVP 'Why don't we jump on a fad that hasn't already been widely discredited ?' - Dilbert
I tried converting the code with a converter I found online but the result didn't seem to be correct. However, I think I understand what you mean, but that's not the problem. Simply put I need to convert a control to it's real type. If I could figure that out I'd be all set. Any thoughts on that? At the moment I have figured out solution. I realized I can convert the control to an object and then add it to the list. As long as Option Strict isn't on this works just fine because it just uses implicit conversion. I'm okay with that for now but I'd still like to know if there is anyway to convert a generic control to it's actual type without knowing it's type a head of time. Here is the code I'm using right now, which is working just fine.
'Returns a control array full of controls that match the desired type Shared Function ControlArray(Of T as control)(ByVal container As Control) As T() 'Controls to pass back Dim list As New List(Of T) For Each ctrl As Control In container.Controls 'If child control is of the desired type T then add to list If ctrl.GetType Is GetType(T) Then list.Add(CType(ctrl, Object)) Next 'Return array Return list.ToArray End Function
-- modified at 20:53 Friday 26th January, 2007 Okay, I take it back what I said about the constraint not being a problem. Well, technically it wasn't a problem but now that I have added a constraint I am now able to add a control type to my list which is of T. Now I don't need to convert to an object first, however, an implicit conversion is still needed so Option Strict can't be turned on. Thanks for your help! It worked perfectly. If you have any ideas on making this option strict friendly please let me know.
-
I tried converting the code with a converter I found online but the result didn't seem to be correct. However, I think I understand what you mean, but that's not the problem. Simply put I need to convert a control to it's real type. If I could figure that out I'd be all set. Any thoughts on that? At the moment I have figured out solution. I realized I can convert the control to an object and then add it to the list. As long as Option Strict isn't on this works just fine because it just uses implicit conversion. I'm okay with that for now but I'd still like to know if there is anyway to convert a generic control to it's actual type without knowing it's type a head of time. Here is the code I'm using right now, which is working just fine.
'Returns a control array full of controls that match the desired type Shared Function ControlArray(Of T as control)(ByVal container As Control) As T() 'Controls to pass back Dim list As New List(Of T) For Each ctrl As Control In container.Controls 'If child control is of the desired type T then add to list If ctrl.GetType Is GetType(T) Then list.Add(CType(ctrl, Object)) Next 'Return array Return list.ToArray End Function
-- modified at 20:53 Friday 26th January, 2007 Okay, I take it back what I said about the constraint not being a problem. Well, technically it wasn't a problem but now that I have added a constraint I am now able to add a control type to my list which is of T. Now I don't need to convert to an object first, however, an implicit conversion is still needed so Option Strict can't be turned on. Thanks for your help! It worked perfectly. If you have any ideas on making this option strict friendly please let me know.
Actually, the core problem is, you're iterating through a collection of controls, looking for objects that are of a more specific type. One solution that would work in C# is the 'as' keyword foreach(Control ctrl in container.Controls) { T specific = ctrl as T; if (specific != null) { list.Add(specific); } } This code makes use of the 'as' keyword, which does a conversion, or returns null if one is not possible. This removes the need for a cast, and replaces the code you've got using GetType ( which is not BAD code, but this approach changes the code rather than adds to it ).
Christian Graus - C++ MVP 'Why don't we jump on a fad that hasn't already been widely discredited ?' - Dilbert
-
Actually, the core problem is, you're iterating through a collection of controls, looking for objects that are of a more specific type. One solution that would work in C# is the 'as' keyword foreach(Control ctrl in container.Controls) { T specific = ctrl as T; if (specific != null) { list.Add(specific); } } This code makes use of the 'as' keyword, which does a conversion, or returns null if one is not possible. This removes the need for a cast, and replaces the code you've got using GetType ( which is not BAD code, but this approach changes the code rather than adds to it ).
Christian Graus - C++ MVP 'Why don't we jump on a fad that hasn't already been widely discredited ?' - Dilbert
Thanks once again for your help. I converted your code and 'as' converted to CType(ctrl, T) which I am familiar with. However, it seems that unlike C# a failed conversion will generate an error. I could do something similiar to your code by using TryCast instead which does return nothing if it fails. I'm not exactly sure what the technical differences are between CType and TryCast (aside from no errors that is). I think I might have to look that up. Now that I have used a constraint, CType and TryCast/Directcast work. Before I used a constraint they would not compile. It seems the constraint was all I needed and allows me to convert a control type to T. Now that I don't need to rely on a implicit conversion Option Strict is happy :)
-
Thanks once again for your help. I converted your code and 'as' converted to CType(ctrl, T) which I am familiar with. However, it seems that unlike C# a failed conversion will generate an error. I could do something similiar to your code by using TryCast instead which does return nothing if it fails. I'm not exactly sure what the technical differences are between CType and TryCast (aside from no errors that is). I think I might have to look that up. Now that I have used a constraint, CType and TryCast/Directcast work. Before I used a constraint they would not compile. It seems the constraint was all I needed and allows me to convert a control type to T. Now that I don't need to rely on a implicit conversion Option Strict is happy :)
CType is not the same, nor is DirectCast. TryCast is the same as the 'as' keyword. Sounds like you've got it working, anyhow :-)
Christian Graus - C++ MVP 'Why don't we jump on a fad that hasn't already been widely discredited ?' - Dilbert