Type parameters cannot be used as qualifiers - vb.net

VB.Net2005
Simplified Code:
MustInherit Class InnerBase(Of Inheritor)
End Class
MustInherit Class OuterBase(Of Inheritor)
Class Inner
Inherits InnerBase(Of Inner)
End Class
End Class
Class ChildClass
Inherits OuterBase(Of ChildClass)
End Class
Class ChildClassTwo
Inherits OuterBase(Of ChildClassTwo)
End Class
MustInherit Class CollectionClass(Of _
Inheritor As CollectionClass(Of Inheritor, Member), _
Member As OuterBase(Of Member))
Dim fails As Member.Inner ' Type parameter cannot be used as qualifier
Dim works As New ChildClass.Inner
Dim failsAsExpected As ChildClassTwo.Inner = works ' type conversion failure
End Class
The error message on the "fails" line is in the subject, and "Member.Inner" is highlighted. Incidentally, the same error occurs with trying to call a shared method of OuterBase.
The "works" line works, but there are a dozen (and counting) ChildClass classes in real life.
The "failsAsExpected" line is there to show that, with generics, each ChildClass has its own distinct Inner class.
My question: is there a way to get a variable, in class CollectionClass, defined as type Member.Inner? what's the critical difference that the compiler can't follow?
(I was eventually able to generate an object by creating a dummy object of type param and calling a method defined in OuterBase. Not the cleanest approach.)
Edit 2008/12/2 altered code to make the two "base" classes generic.

Dim succeeds as OuterBase.Inner
.net does not have C++'s combination of template classes and typedefs, which means what you are trying to do is not possible, nor does it even make sense in .net.

ChildClass.Inner and SomeOtherChildClass.Inner are the same type. Here's a short but complete program to demonstrate:
Imports System
MustInherit Class InnerBase
End Class
MustInherit Class OuterBase
Class Inner
Inherits InnerBase
End Class
End Class
Class ChildClass
Inherits OuterBase
End Class
Class OtherChildClass
Inherits OuterBase
End Class
Class Test
Shared Sub Main()
Dim x as new ChildClass.Inner
Dim y as new OtherChildClass.Inner
Console.WriteLine(x.GetType())
Console.WriteLine(y.GetType())
End Sub
End Class
The output is:
OuterBase+Inner
OuterBase+Inner
What were you trying to achieve by using "parameterised" nested classes? I suspect that either it wouldn't work how you'd want it to, or you can achieve it just by using OuterBase.Inner to start with.
Now if each of your child classes were declaring their own nested class, that would be a different situation - and one which generics wouldn't help you with.

Related

Why base classes must have default new?

I got this error
https://learn.microsoft.com/en-us/dotnet/visual-basic/misc/bc30387
And I wonder why.
What about if I never want to call parameterless new in both base and derived classes?
I can do that if I don't use inheritance. Why using inheritance means I can no longer do so?
To repeat the issue
What's the explanation? So NOT every classes need parameterless new but classes with inheritance must? That doesn't make sense.
What about if I never call derived class with parameter less constructor. I don't intent for the class to ever be constructed without parameter.
For example, say, I want to create a class without parameterless constructor. I can do that right.
But say I want to split the class into two. Parent and child class. I want BOTH not to ever have parameterless constructor.
It seems that I can't do that can I? If such is the case, can anyone please confirm it.
The link says that if you have an explicit constructor in your base class with parameters and no parameterless one than you cannot leave your derived class without constructor. Because VB.NET cannot create an implicit constructor for derived class.
If you don't write any constructors for both, it is perfectly valid.
public class Base
End Class
Public Class Derived
Inherits Base
End Class
However you cannot declare a derived class without an explicit constructor like below. Because VB.NET cannot determine how to initialize base class.
public class Base
Public sub New(ByVal Item As Integer)
End Sub
End Class
Public Class Derived
Inherits Base
End Class
To overcome this issue you can declare a default constructor on derived class which calls base class constructor with a default value.
public class Base
Public sub New(ByVal Item As Integer)
End Sub
End Class
Public Class Derived
Inherits Base
Public Sub New()
MyBase.New(5)
End Sub
End Class

Too many identical simple methods using an interface

I have a few dozen classes which all implement the same interface and many of the methods have identical implementation. I have to do a lot of copy and paste whenever I add a new class. How can I get less code duplication?
I've heard that you should put the common code in a helper class but a lot of these methods are really trivial so calling a helper method is barely any simpler than doing the actual work.
Inheritance would save re-declaring all these methods but it would make it messy for the few classes that don't have the identical implementation.
Examples:
Identical in nearly every class...
Public Sub ThingWasDeleted(ByVal deletedThing As Thing) Implements Iinterface.ThingWasDeleted
If MyThing Is deletedThing Then
MyThing = Nothing
End If
End Sub
...but occasionally different:
Public Sub ThingWasDeleted(ByVal deletedThing As Thing) Implements IInterface.ThingWasDeleted
'Do nothing
End Sub
Identical in every class but already just as simple as calling a common helper method:
Public ReadOnly Property DisplayName() As String Implements IInterface.DisplayName
Get
Return DisplayNameShared
End Get
End Property
If you put these methods in a helper class, wouldn't that make it just as messy (if not more) than having an abstract base class where you can override the base class's functionality when needed?
For example:
Public MustInherit Class BaseClass
Public ReadOnly Property DisplayName() As String
Get
Return DisplayNameShared
End Get
End Property
Public Overridable Sub ThingWasDeleted(ByVal deletedThing As Thing)
If MyThing Is deletedThing Then
MyThing = Nothing
End If
End Sub
End Class
This provide a definition of the property that all inheriting classes can use, and gives the inheriting class an option to override and create their own implementation of ThingWasDeleted.
For example:
Public Class MyClass
Inherits BaseClass
Public Overrides Sub ThingWasDeleted(ByVal deletedThing As Thing)
' Do nothing
End Sub
End Class
On the other hand, if you wrote a helper class, you'd have to define every method, and the developer (which may or may not be you) would have to know which method to change. Additionally, instead of having the option to use the existing functionality in the base (abstract) class, every class you create will have to call each of the proper helper methods.
Personally, I prefer the former option, mainly because the inheriting classes don't have to call anything to get the base functionality established in the base class, and can override what they need to on a case-by-case basis. Conversely, having them all in a helper class means you have to at least write the code to call each of the necessary helper methods in every class you have.

How to get the class type in a inherited shared method

Folks;
Code looks like:
Public Class MasterA
Inherits Underling
End Class
Public Class MasterB
Inherits Underling
End Class
Public Mustinherit Class Underling
Sub DoSomething()
Me.GetType 'Using the instance, I can get the class.
end sub
Shared function() as ???? 'How can I define the return type based on the class that inherited me?
'Me.GetType 'Won't work as this is a shared function with no instance 'Me'
End Function
End class
OK. The question is: is there a way to get at the class type from within a shared function that was inherited by another class?
What I'm building is an XML serializer/desrializer as an inheritable class so that classes that inherit it can be serilized to an XML file, and back again. Rather than writing a serializer/deserializer for each type of class I want to do this with, I'd like to just inherit the functionality.
To do that, though, requires that I be able to ascertain the clas that inherited me in the shared function.
You could get the desired behavior with a generic base class, my VB is a little rusty so you might find stray parens or brackets. This would really be the only way to get a type reference to an inheriting class in a shared base class function.
Public Mustinherit Class Underling(Of T)
Sub DoSomething()
Me.GetType 'Using the instance, I can get the class.
end sub
Shared function() As T
' GetType(T) should get the type at this point
End Function
End class
Public Class MasterA
Inherits Underling(Of MasterA)
End Class
Public Class MasterB
Inherits Underling(Of MasterB)
End Class
As a side note it does seem like a rather weird solution to handle XmlSerialization rather than through your own serializer implementation or XmlSerializer

Error when passing friend class as type from public class to friend base class

Disclaimer: I am fairly new to working with generics so I am not entirely sure if what I am trying to do even makes sense or is possible.
I have a bunch of user controls in a project. All of these user controls share a similar property so I want to move it into a base class. The only difference is the return type of the property.
I have three classes interacting in this scenario. The first class is a base type, which inherits from CompositeControl and will be inherited by other classes in my project:
Friend Class MyBaseClass(Of T As {New})
Inherits CompositeControl
Private _someProperty As T = Nothing
Protected ReadOnly Property SomeProperty As T
Get
// dumbed down for the sake of example
If _someProperty Is Nothing Then
_someProperty = New T()
End If
Return _someProperty
End Get
End Property
End Class
Then I have this control class, which inherits from MyBaseClass:
Public Class MyControlClass
Inherits MyBaseClass(Of MyReturnTypeClass)
// snip...
End Class
And finally MyReturnTypeClass which is what the base's SomeProperty should return:
Friend Class MyReturnTypeClass
Public Property AutoProperty1 As Boolean = False
Public Property AutoProperty2 As String = String.Empty
// etc
End Class
When I attempt to build the project, I get this error from MyControlClass:
Inconsistent accessibility: type argument 'MyReturnTypeClass' is less accessible than Class 'MyControlClass'.
I need MyControlClass to be Public so it can be consumed by other projects, and I also want the MyBaseClass and MyReturnTypeClass to be Friend so they cannot be seen/used by consumers. Am I just missing some special keyword somewhere or is this not possible?
You cannot inherit from a base class that is less accessible than the derived class. So for instance, this won't work:
Friend Class MyBase
End Class
Public Class MyDerived
Inherits MyBase ' Won't compile because MyBase is less accessible
End Class
Therefore, since in your example, MyBaseClass(T) has is a friend type, but you are trying to inherit from it into a public MyControlClass type. Therefore, even if you took generics and MyReturnTypeClass out of the "equation", it still wouldn't work.
However, with generics, even if no member of the public interface of the class actually uses the generic type, the type must still be at least as accessible as the derived type. For instance:
Public Class MyBase(Of T)
' T not actually used at all
End Class
Friend Class MyOtherType
End Class
Public Class MyDerived
Inherits MyBase(MyOtherType) ' Won't compile because MyOtherType is less accessible
End Class
The base class must be at least as accessible as the derived class. This is a language restriction (see here).
If you intend to avoid MyBaseClass being instantiated by consumers, consider marking it Public MustInherit instead of Friend. Hope this helps.

How do I code these generic functions and classes inheritances correctly? (VB .NET)

I have a function which I need to call for three different types, with the underlying logic remaining the same for all the different types, so I figured it would be best to write this function using generics.
Here is the basic outline of the classes and functions involved:
'PO Base class'
Public MustInherit Class ProductionOrder
Public MustInherit Class Collection(Of T)
Inherits System.Collections.Generic.Dictionary(Of Long, T)
End Class
'....'
End Class
Public Class ProfileProductionOrder
Inherits ProductionOrder
Public Class Collection
Inherits ProductionOrder.Collection(Of ProfileProductionOrder)
End Class
'....'
End Class
Public Class UnitProductionOrder
Inherits ProductionOrder
Public Class Collection
Inherits ProductionOrder.Collection(Of UnitProductionOrder)
End Class
'....'
End Class
Public Class CrateProductionOrder
Inherits ProductionOrder
Public Class Collection
Inherits ProductionOrder.Collection(Of CrateProductionOrder)
End Class
'....'
End Class
'Generic function, intended to work on profile, unit, and crate production orders.'
'This method resides in the base class of the GUI.'
Protected Sub FillPOCells(Of T As ProductionOrder.Collection(Of ProductionOrder)) _
(ByVal dgv As DataGridView, ByVal ProductionOrders As T)
'...do some stuff'
End Sub
'This function resides in the Profile child GUI class.'
Protected Sub LoadDataGridViewPOs()
Dim dgv As DataGridView
Dim ProductionOrders As ProfileProductionOrder.Collection
'....'
'Fill PO Cells'
FillPOCells(Of ProfileProductionOrder.Collection)(dgv, ProductionOrders)
'....'
End Sub
The ProductionOrder base and child classes compile, as does the FillPOCells function. But when I call FillPOCells inside LoadDataGridViewPOs the compiler complains that "Type argument 'ProfileProductionOrder.Collection' does not inherit from or implement the constraint type 'ProductionOrder.Collection(Of ProductionOrder)'.
Also, here is some explanation about why things are set up this way. My predecessor set up the convention of putting the collection of an object as a subclass within it, so it's easy to refer to it as Obj.Collection. Next, the reason we need three different types of production orders is because they are treated differently and stored in different tables and such on the back end. Lastly, I realize I could implement this fairly easily without getting this particular generic function to work, but I'm looking at this as a learning experience to improve my understanding of generics and OO design.
So the question is, why am I getting that compiler error and how should I change my class and generics design to accomplish what I have in mind?
If you need any further explanation about what I'm trying to do or how I have things set up let me know. The main idea is to have a function that can take a collection who's elements belong to one of the ProductionOrder child classes, and run operations on these elements that only use the functionality held in their ProductionOrder base class (hence why either of the child types is okay to operate on in the function).
'PO Base class'
Public MustInherit Class ProductionOrder(Of T)
Public MustInherit Class Collection
Inherits System.Collections.Generic.Dictionary(Of Long, T)
End Class
'....'
End Class
Public Class ProfileProductionOrder
Inherits ProductionOrder(Of ProfileProductionOrder)
'....'
End Class
Public Class UnitProductionOrder
Inherits ProductionOrder(Of UnitProductionOrder)
'....'
End Class
Public Class CrateProductionOrder
Inherits ProductionOrder(Of CrateProductionOrder)
'....'
End Class
That is a lot simpler according to me.
But I higly doubt you need the CollectionClass.