locked
Generics C# to VB.NET Problem RRS feed

  • Question

  • User-691759321 posted

    I am trying to convert the ExcelLibrary to VB.NET to better align it with a control set I am working on.  However, after I translate the following code:

    public class BinarySearchTreeBase<TItem, TTreeNode>
         where TItem : IComparable<TItem>

    it becomes:

    Public Class BinarySearchTreeBase(Of TItem As IComparable(Of TItem), TTreeNode)

    However, in C# you apparently do not need to implement the IComparable function CompareTo in order to perform an = or != operation.  In VB.NET however I am getting the following errors:

    "Operator = not defined for types ... and ...

    Anyone know how to fix this conversion for generics?

    Tuesday, April 19, 2011 11:37 AM

All replies

  • User-964259575 posted

    Are you maybe mixing up the classes? It's the TItem class that implements the IComparable interface, not the BinarySearchTreeBase class.

    I don't know anything about the VB syntax for generics and interfaces etc. but the following example is valid C#.

    public class BinarySearchTreeBase<TItem, TTreeNode> where TItem : IComparable<TItem>
    {
        // The BinarySearchTreeBase class does not implement IComparable<>
    }
    
    public class SomeItem : IComparable<SomeItem>
    {
        // The SomeItem class does implement the IComparable<> interface,
        // so this method has to be implemented
        public int CompareTo(SomeItem other)
        {
            return 0; // do the real comparison here
        }
    }

    Saturday, April 23, 2011 4:37 PM
  • User-691759321 posted

    The problem is the TItem is listed as implementing IComparable however in the C# code there is no CompareTo method for TItem.  Therefore, in the base methods whenever the code performs a TItem = TItem I get the error error message.  How does this even work in C# if there is no CompareTo method?  Is VB.NET the only language smart enough to see the problem with this?  Since TItem is generic, not specific to one class, how can I create a CompareTo method? 

    Thursday, May 12, 2011 10:36 AM
  • User-964259575 posted

    The "TItem" in the definition of the BinarySearchTreeBase class is just a "placeholder", or kind of a variable. In the code for BinarySearchTreeBase you assume that the TItem is implementing the IComparable<> interface. However, the BinarySearchTreeBase does not know anything about how the IComparable<> interface is implemented, since it don't know which class will be substituted for TItem when a BinarySearchTreeBase object is instantiated.

    I don't know how to best explain it, but there is no class TItem. When you instantiate a BinarySearchTreeBase object, you have to specify a concrete class which implements IComparable<> (and you also have to specify a second class, for TTreeNode, but that class has no interface restrictions).

    ...however in the C# code there is no CompareTo method for TItem.

    I'm not sure what you mean with this. It's not the BinarySearchTreeBase that implements IComparable<>, and thus the BinarySearchTreeBase don't have to have a CompareTo() method. But when you write a class that implements an interface, you have to write implementations for everything in the interface, or you will get compile error. I guess it's the same in VB, but I only write C# myself.

    Since TItem is generic, not specific to one class, how can I create a CompareTo method?

    I don't agree. It's the BinarySearchTreeBase class that is generic.

    Thursday, May 12, 2011 2:42 PM
  • User-691759321 posted

    That is the basis of the question.  You DO NOT have to specify a specific class to implement IComparable.  Download the ExcelLibrary C# code and open the section for the BinarySearchTreeBase.  You will notice the code is a direct copy from C# to VB.NET but the C# code does not appears to complain of the lines where TItem is compared to another TItem.  I am not sure if VB.NET is just smarter when it comes to the validation of the code or if C# is just opening itself to weird bugs by not catching this problem.  Using generics for this does make sense though seeing as the type could be any type that already implements IComparable.  Perhaps that is what it is after but I am not sure how to say the generic parameter TItem must be a class that implements IComparable.  In that case the CompareTo would already be guaranteed to be defined.  This may just be one of those cases that does not convert from one language to another.

    Thursday, May 19, 2011 11:40 AM
  • User-964259575 posted

    I've never done anything in VB, but I write C# every day at work. As far as I can see these two snippets from your original post are identical

    public class BinarySearchTreeBase<TItem, TTreeNode>
         where TItem : IComparable<TItem>
    
    Public Class BinarySearchTreeBase(Of TItem As IComparable(Of TItem), TTreeNode)

    However you say

    in C# you apparently do not need to implement the IComparable function CompareTo in order to perform an = or != operation

    That's right! Look at the IComparable<> interface, http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx The only method in the interface is CompareTo. Is says nothing about = and != operators. Now time for bed...

    Friday, May 20, 2011 6:53 PM
  • User-964259575 posted

    Look at this example

    public class Foo : IComparable<Foo>
    {
        public int Value { get; set; }
    
        public int CompareTo(Foo other)
        {
            return this.Value.CompareTo(other.Value);
        }
    }

    This class implements IComparable<> and thus must have a CompareTo()-method.

    Now...

    Foo f1 = new Foo { Value = 1 };
    Foo f2 = new Foo { Value = 2 };
    Foo f3 = new Foo { Value = 1 };
    
    bool b1 = f1 == f2; // false
    bool b2 = f1 == f3; // false
    
    int i1 = f1.CompareTo(f2); // -1
    int i2 = f1.CompareTo(f3); // 0

    The variable b1 is false, not surprisingly. The variable b2 is also false, because f1 and f3 are two different objects. No matter they happen to have the same value for the property called Value.

    The variable i1 is -1 because the two objects' Value property are compared, and the result -1 tells us that f1 is "less than" f2.

    The interesting thing here is the variable i2 which is zero, indicating that f1 "is equal to" f2. But only in terms of comparing. Not in terms of equality, so to speak. Confusing? Maybe, but still logical.

    There is another interface called IEquatable<>, which may be of interest to you.

    And also you could override the operator= and operator!= (http://msdn.microsoft.com/en-us/library/s53ehcz3.aspx)

    Sunday, May 22, 2011 9:43 AM
  • User-691759321 posted

    While both of your example show how to implement a "standard" IComparable interface class it still does not solve the initial problem.  If you try to use the code base I am try (ExcelLibrary) and converting the Binary Search classes to VB.NET it will not compile.  Please read what I have written carefully.  Implementing an IComparable class is extremely easy, however, in this particular case it is implementing an IComparable GENERIC class which does not have a defined structure or CompareTo method defined.  For some reason in C# this is not a problem but in VB.NET it does not compile.  I am not sure how to make a generic parameter part of the IComparable interface.  When I try to implement the CompareTo method on the TItem object it does not work because it is not in the TItem class definition, which doesn't exist because it is generic.  The whole idea just doesn't seem logical yet C# has no problems.  I am looking for an explanation on this phenominon and why it does not work in VB.NET or if there is a way to make it work.

    Tuesday, May 24, 2011 9:24 AM
  • User-964259575 posted

    Well, I don't think I completely understand. When I look at the code at http://code.google.com/p/excellibrary/.../BinarySearchTreeBase.cs the TItem's CompareTo() method I guess is used e.g. on line 96. Could you give an example of where the class BinarySearchTreeBase is instantiated? Probably in some other class in the library (but I don't want to search all files...). It would be interesting to see an example of a concrete class for "TItem".

    Tuesday, May 24, 2011 4:24 PM
  • User-691759321 posted

    The BinarySearchTreeBase is used by the RedBlackTree class which is used in the DirectoryTree class.  The RedBlackTree takes a single parameter of the type of nodes.  In this case the node type is a DirectoryEntry.  Even taking the simplest of examples from the BinaryTreeNodeBase and converting the code to VB.NET it doesn't compile.  I guess there is no way to write the conversion to VB.NET.

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    
    Public Class BinaryTreeNodeBase(Of TItem, TTreeNode As BinaryTreeNodeBase(Of TItem, TTreeNode))
        Public Data As TItem
        Public Parent As TTreeNode
        Public Left As TTreeNode
        Public Right As TTreeNode
    
        Public ReadOnly Property IsLeftChild As Boolean
            Get
                Return Me = Parent.Left
            End Get
        End Property
    
        Public ReadOnly Property IsRightChild As Boolean
            Get
                Return Me = Parent.Right
            End Get
        End Property
    End Class
    
    

    UPDATE: Once I looked at the code some more I found the main issue for the code above stems from VB.NET's lack of understanding.  It recognizes that TTreeNode is a BinaryTreeNodeBase(Of TItem, TTreeNode) however the = signs do not recognize this and it gives an error saying it cannot compare type TTreeNode to BinaryTreeNodeBase(Of TItem, TTreeNode).  Maybe the "As" in the class creation is not the proper way to define this for the class but as I said before...C# apparently does not have any problems with this code.

    Wednesday, May 25, 2011 9:11 AM
  • User-964259575 posted

    So, TTreeNode is a BinaryTreeNodeBase(Of TItem, TTreeNode), that's what is expressed in the class definition.

    "Me" is of course a BinaryTreeNodeBase(Of TItem, TTreeNode).

    Parent is a TTreeNode, which is a BinaryTreeNodeBase(Of TItem, TTreeNode).

    Because of this, we also see that Parent.Left is a BinaryTreeNodeBase(Of TItem, TTreeNode).

    So, checking for equality between Me and Parent.Left should not be a problem, since both are BinaryTreeNodeBase(Of TItem, TTreeNode). And as you say, C# has no problem with this. I'm not a VB expert, so I really don't know why it doesn't work in VB.

    You could try to write it more explicit. I have modified the C# code a little bit. Try converting it to VB.

    public class BinaryTreeNodeBase<TItem, TTreeNode>
        where TTreeNode : BinaryTreeNodeBase<TItem, TTreeNode>
    {
        public TItem Data;
    
        public TTreeNode Parent;
    
        public TTreeNode Left;
    
        public TTreeNode Right;
    
        public bool IsLeftChild
        {
            get
            {
                BinaryTreeNodeBase<TItem, TTreeNode> thisNodeBase = this;
    
                TTreeNode left = Parent.Left;
                BinaryTreeNodeBase<TItem, TTreeNode> leftNodeBase = left;
    
                return thisNodeBase == leftNodeBase;
            }
        }
    
        public bool IsRightChild
        {
            get { return this == (BinaryTreeNodeBase<TItem, TTreeNode>)(Parent.Right); }
        }
    }

    Basically it should be the same problem with the following example, which is a bit more simple.

    //using System.Collections.Generic;
    
    List<int> myList = new List<int>();
    IList<int> myIList = myList;
    
    bool isSame = myList == myIList; // true

    Thursday, May 26, 2011 4:53 PM