locked
Binding List (of T) - Value of Type 'T' cannot be converted

    Question

  • Hi There,

    I've set up a base class which uses BindingList(of T). This has proved useful for different collection based screens to manage lists of Business Objects.

    In the past, I have created list classes with business object classes specified and added validation functions to check for the occurence of conditions within the business objects of that list.

    In this new project, I have a condition to search for which applies to a specific type of business object.
    The code looks like this:

    public function ConditionExists(nContractorID as int) as boolean
        dim bResult as boolean = false
        for each entry as T in Me.m_List
            if CType(entry, Contractor).ContractorID = nContractorID then
                bResult = true
            end if
        next
        return bResult
    end function

    (Assume this function will only be called when the list is of type contractor)

    The compiler throws an error saying it can't convert type 'T' to contractor. When populating the lists, I've used GetType(T) to determine the type of list, and Activator.CreateInstance to add items to the list.

    Is there a similar method I can use to convert a list entry back to it's original type to access it's properties?

    Thanks in Advance
    Jim
    Intermediate Google goodies trawler...
    Monday, March 09, 2009 11:17 AM

Answers

  • Hi Jim.  There's a little-discussed (at least that I've seen) option with generics that allows you to narrow the types allowed for the "T" argument -- useful for inheritance situations where multiple inherited classes will only be used in the generic class.  See my example below that attempts to simulate the basics of your code example -- the option I mentioned is highlighted...

     
    Public Class Test(Of T As Entry)  
     
        Public m_List As New List(Of T)  
     
        Public Function DoesContractorIdExist(ByVal value As Int32) As Boolean 
     
            Dim bResult As Boolean = False 
            For Each item As T In Me.m_List  
                If CType(item, Contractor).ContractorId = value Then 
                    bResult = True 
                End If 
            Next 
            Return bResult  
     
     
        End Function 
     
    End Class 
     

    Without that As clause in the class declaration I got the compiler error saying it could not perform the cast -- but after adding it the exception went away.  Hope this works for you -- but remeber that it will not work if you are collecting other class types in m_List.

    DB
    Monday, March 09, 2009 3:09 PM
  • You can also use Object as a temporary variable type and then cast after checking with TypeOf function...

     
      Public Function DoesIdExist(ByVal value As Int32) As Boolean 
     
            Dim bResult As Boolean = False 
            For Each entry As Object In Me.m_List  
                If TypeOf (entry) Is Contractor Then 
                    If CType(entry, Contractor).ContractorId = value Then 
                        bResult = True 
                    End If 
                End If 
            Next 
            Return bResult  
     
        End Function 
     

    I'm not sure if this is what _asgar meant by using Object -- I though maybe it was referring to making the class (Of Object) instead of (Of T) -- which I suppose could work but then seems out of place...  I never see example of generics using (Of Object) and it may be that this pattern would negate the usefulness of generics..


    Monday, March 09, 2009 3:15 PM

All replies

  • you should use Contractor or  Object  instead of T . T is a PlaceHolder for the Data Type to be used in the BindingList.
    Monday, March 09, 2009 12:48 PM
  • Hi
     
    But using the class as generic has proved very useful, and I've used it in a number of places. One possible solution (rather than the "you can't do it" scenario) is to derive another class from the binding class for the specific bo list. Although this might be a neat solution, I want to be sure that a workaround isn't possible.

    Jim

    Intermediate Google goodies trawler...
    Monday, March 09, 2009 1:15 PM
  • Hi Jim.  There's a little-discussed (at least that I've seen) option with generics that allows you to narrow the types allowed for the "T" argument -- useful for inheritance situations where multiple inherited classes will only be used in the generic class.  See my example below that attempts to simulate the basics of your code example -- the option I mentioned is highlighted...

     
    Public Class Test(Of T As Entry)  
     
        Public m_List As New List(Of T)  
     
        Public Function DoesContractorIdExist(ByVal value As Int32) As Boolean 
     
            Dim bResult As Boolean = False 
            For Each item As T In Me.m_List  
                If CType(item, Contractor).ContractorId = value Then 
                    bResult = True 
                End If 
            Next 
            Return bResult  
     
     
        End Function 
     
    End Class 
     

    Without that As clause in the class declaration I got the compiler error saying it could not perform the cast -- but after adding it the exception went away.  Hope this works for you -- but remeber that it will not work if you are collecting other class types in m_List.

    DB
    Monday, March 09, 2009 3:09 PM
  • You can also use Object as a temporary variable type and then cast after checking with TypeOf function...

     
      Public Function DoesIdExist(ByVal value As Int32) As Boolean 
     
            Dim bResult As Boolean = False 
            For Each entry As Object In Me.m_List  
                If TypeOf (entry) Is Contractor Then 
                    If CType(entry, Contractor).ContractorId = value Then 
                        bResult = True 
                    End If 
                End If 
            Next 
            Return bResult  
     
        End Function 
     

    I'm not sure if this is what _asgar meant by using Object -- I though maybe it was referring to making the class (Of Object) instead of (Of T) -- which I suppose could work but then seems out of place...  I never see example of generics using (Of Object) and it may be that this pattern would negate the usefulness of generics..


    Monday, March 09, 2009 3:15 PM
  • Thanks DigBoy,

    Both solutions look interesting. The second one looks good for the one type of class validation scenario.
    The As looks a little restrictive, will this not make my binding class only work with one type of object?

    Jim

    Intermediate Google goodies trawler...
    Monday, March 09, 2009 3:26 PM
  • SpodgyTwoSugars said:

    Thanks DigBoy,

    Both solutions look interesting. The second one looks good for the one type of class validation scenario.
    The As looks a little restrictive, will this not make my binding class only work with one type of object?

    Jim


    Intermediate Google goodies trawler...




    Kind of...  If your one type of object is an interface, say, then you caould be talking about conceivably dozens of object types.  And since MustInherit classes are very similar to interfaces, then inheritance could be another approach.  Both approaches support future extensibility in your classes making them more dynamic.
    Monday, March 09, 2009 4:38 PM
  • Thanks again,

    I finally opted for a derived class, based upon the object I needed the validation for.

     

    Public Class ContractorSiteList  
        Inherits BusinessBaseList(Of ContractorSite)  
     
        Public Shadows ReadOnly Property List() As BindingList(Of ContractorSite)  
            Get  
                Return MyBase.List  
            End Get  
        End Property  
     
        Public Sub New(ByVal nSiteID As Integer)  
            MyBase.New(nSiteID)  
        End Sub  
     
        Public Function ReturnContractor(ByVal eWT As Common.eWasteStream) As Contractor  
            For Each CS As ContractorSite In MyBase.List  
                If CS.WasteStreamType.WasteStreamTypeID.Value = eWT Then  
                    Return CS.Contractor  
                End If  
            Next  
            Return Nothing  
        End Function  
     
        Public Function ValidateContractor(ByVal eWT As Common.eWasteStream) As Boolean  
            ValidateContractor = False 
            For Each CS As ContractorSite In MyBase.List  
                If CS.WasteStreamType.WasteStreamTypeID.Value = eWT Then  
                    ValidateContractor = True 
                End If  
            Next  
        End Function 

    Jim


    Intermediate Google goodies trawler...
    Monday, March 09, 2009 5:03 PM