Is there a way to spread interface implementation over class hierarchy? Consider following example.
Public Interface I
Property X As String
Property Y As String
Property Z As String
End Interface
Public Class A
Property X As String
Property Y As String
End Class
Public Class B
Inherits A
Implements I
Property Z As String
End Class
I'd like to avoid to repeat X and Y in B. Think about ten instead of two.
And I don't want to split interface I because inheritance of B should be implementation detail.
This might not work for your situation but you could use Partial Classes.
This means you will lose class A :-(
Are you using MVC Razor HTML helper classes? I don't think they like it when as interface isn't implemented in a single class.
Public Interface I
Property X As String
Property Y As String
Property Z As String
End Interface
Partial Public Class B
Property X As String Implements I.X
Property Y As String Implements I.Y
End Class
Public Class B
Implements I
Property Z As String Implements I.Z
End Class
Not sure how else to tackle this one...
EDIT:
Public Interface iA
Property X As String
Property Y As String
End Interface
Public Interface iB
Property Z As String
End Interface
Public Interface IAB
Inherits iA
Inherits iB
End Interface
Public Class A
Implements iA
Property X As String Implements iA.X
Property Y As String Implements iA.Y
End Class
Public Class B
Inherits A
Implements IAB
Property Z As String Implements iB.Z
End Class
Related
I have a case as follows (VB.NET):
class A (contains some fields)
class B inherits List(Of A)
class C (contains some fields)
class D inherits List(Of C)
There are some common Methods and Functions that I want them to be centralized and act on both classes B & D, without the need to re-write them and keep them updated under both classes.
Those common Methods and Functions act on identical fields (name and type) in both classes A and C.
What should I do? And why to inherit from List(Of T) is considered a bad idea?
My solution was to create new Abstract (MustInherit) class X and moves the common fields from Classes A & C to class X. Then created a 'Friend' Module that has those common methods and functions (targeting the common fields between classes A & C) which takes IEnumerable(Of class X) .. and voila!
Any comments on such implementation??
Thanks
The below is my solution using IEnumerable, but using a shared function in a separate module.
Public MustInherit Class ProbSts 'class X
Public Status As Boolean
Public Probability, Min, Max As Integer
End Class
Public NotInheritable Class SIPRouteProbabilityStatus 'class A
Inherits ProbSts
Public Route As SIPRoute
End Class
Public NotInheritable Class SIPRGProbabilityStatus ' class C
Inherits ProbSts
Public RG As SIPRouteGroup
End Class
Public NotInheritable Class SIPRouteProbabilityStatusCollection ' class B
Inherits List(Of SIPRouteProbabilityStatus)
Public ProbabilityTotal As Integer
Public Function TotalProbability(Optional Status As Boolean? = Nothing) As Integer
Return TotalProbabilityAction(Me, Status)
End Function
End Class
Public NotInheritable Class SIPRGProbabilityStatusCollection 'class D
Inherits List(Of SIPRGProbabilityStatus)
Public ProbabilityTotal As Integer
Public Function TotalProbability(Optional Status As Boolean? = Nothing) As Integer
Return TotalProbabilityAction(Me, Status)
End Function
End Class
Friend Module ProbabilityAction
Public Function TotalProbabilityAction(ProbStsList As IEnumerable(Of ProbSts), Optional Status As Boolean? = Nothing) As Integer
Dim sum As Integer = 0
For Each x In ProbStsList
If Status.HasValue Then
If x.Status = Status.Value Then sum += x.Probability
Else
sum += x.Probability
End If
Next
Return sum
End Function
End Module
There is nothing wrong with inheriting from List(Of T) when done properly. It's hard to give the best solution without seeing your classes and how you're using them, but your solution of inheriting from an abstract class is one way of solving it. However from your description, implementing an interface seems to be a better fit. Convert X to an interface with the common fields and you'll be good to go. The actual fields will stay in class A and C, yet the external functions will know how to access and use them.
What's the difference between using an interface vs. an abstract class in your case?
Interface: it only defines the common fields and methods of the classes and leaves the implementation to them.
Abstract Class: It actually hosts the common fields and methods with the implementation so the classes don't need to duplicate the code in case it is the same.
EDIT I don't know if this is the best solution, because I need to see how all these classes are used in your code, but you can get rid of the module by converting it to a class that inherits from List(Of T) and then inherit this class instead of List(Of T) in your B and D classes. Something like this:
Public MustInherit Class ProbSts 'class X
Public Status As Boolean
Public Probability, Min, Max As Integer
End Class
Public NotInheritable Class SIPRouteProbabilityStatus 'class A
Inherits ProbSts
Public Route As SIPRoute
End Class
Public NotInheritable Class SIPRGProbabilityStatus ' class C
Inherits ProbSts
Public RG As SIPRouteGroup
End Class
Public MustInherit Class ProbabilityAction(Of T)
Inherits List(Of T)
Public Function TotalProbabilityAction(ProbStsList As IEnumerable(Of ProbSts), Optional Status As Boolean? = Nothing) As Integer
Dim sum As Integer = 0
For Each x In ProbStsList
If Status.HasValue Then
If x.Status = Status.Value Then sum += x.Probability
Else
sum += x.Probability
End If
Next
Return sum
End Function
End Class
Public NotInheritable Class SIPRouteProbabilityStatusCollection ' class B
Inherits ProbabilityAction(Of SIPRouteProbabilityStatus)
Public ProbabilityTotal As Integer
Public Function TotalProbability(Optional Status As Boolean? = Nothing) As Integer
Return TotalProbabilityAction(Me, Status)
End Function
End Class
Public NotInheritable Class SIPRGProbabilityStatusCollection 'class D
Inherits ProbabilityAction(Of SIPRGProbabilityStatus)
Public ProbabilityTotal As Integer
Public Function TotalProbability(Optional Status As Boolean? = Nothing) As Integer
Return TotalProbabilityAction(Me, Status)
End Function
End Class
I kept the original name of the module ProbabilityAction, but it's recommended to change it to a more suitable name for a base class. I also followed your way and qualified it with MustInherit, but you can decide if you want that or not.
I'm struggling to get this hierarchy working with generics. The problem is that Items is generic, specified at the inheritance level, therefore I cannot cast back to BaseItem, i.e. casting from SpecialItem(Of ExtraSpecialItem) to IItemHost(Of BaseItem) when SpecialItem inherits BaseGroup, as BaseGroup implements IItemHost.
What am I doing wrong here?
Public MustInherit Class BaseItem
Public Property ItemNameOrSomething As String
End Class
Public Interface IItemHost(Of TItemType As {BaseItem})
Property Items As BindingList(Of TItemType) '-- No Out parameter allowed :(
End Interface
Public Class BaseGroup(Of TGroup AS {BaseItem})
Inherits BaseItem
Implements IItemHost(Of TGroup)
'-- This is the key property, all BaseGroup implimentors need an Items property of their specific type
Public Property Items As New BindingList(Of TGroup)() Implements IItemHost(Of TGroup).Items
End Class
Public Class SpecialItem
Inherits BaseGroup(Of ExtraSpecialItem)
End Class
Public Class ExtraSpecialItem
Inherits BaseGroup(Of LeafItem)
End Class
Public Class LeafItem
Inherits BaseItem
End Class
For the most part, this all actually works. What I cannot do is:
Dim root = New SpecialItem()
root.ItemNameOrSomething = "Testing 1"
root.Items.Add(New ExtraSpecialItem() With {.ItemNameOrSomething = "Testing 2"})
'-- This specifically, no casting options available.
Dim item = CType(root, IItemHost(Of BaseItem))
Dim subItems = item.Items
Dim testing2Text = subItems.First().ItemNameOrSomething '-- = "Testing 2"
Ok this hasn't exactly solved the problem, but it's a solution I'm willing to settle with for now.
If I change my BaseItem to have a "BaseItems" collection, my inherited BaseGroup classes can have a default Items IEnumerable. If I need to write back to this collection, I can simply use BaseItems. For standard looping through the items, I can use Items and this will give me the proper casting.
Public MustInherit Class BaseItem
Public Property ItemNameOrSomething As String
Public Property BaseItems As New BindingList(Of BaseItem)()
End Class
Public Class BaseGroup(Of TGroup As {BaseItem})
Inherits BaseItem
Public ReadOnly Property Items As IEnumerable(Of TGroup)
Get
Return BaseItems.Cast(Of TGroup)()
End Get
End Property
End Class
In Visual Basic, I want to create an interface that includes a function that returns an object of the implementing class. That is
public interface I
function maker as ???
end interface
public class X
implements I
function maker as X
return new X()
end function
end class
public class Y
implements I
function maker as Y
return new Y()
end function
end class
Is there a way to say that? I suppose I could always say that maker returns an I rather than an X or a Y, but then callers would have to cast it. I thought of defining the interface as
public interface I(of ii as I)
But the whole point in doing this was so I could create a generic class that uses an of I, and if I say that, then the compiler insists on an infinite regression of I(of I(of I...
Not exactly, but you can do this:
Public Interface I(Of T)
Function Maker() As T
End Interface
Public Class X
Implements I(Of X)
Public Function Maker() As X Implements I.Maker
Return New X()
End Function
End Class
Or, like this:
Public Interface I
Function Maker() As I
End Interface
Public Class X
Implements I
Public Function Maker() As I
Return New X()
End Function
End Class
Neither of these options force the derived class to return an instance of their own type, but they allow you to implement it that way.
This is where you need the "curiously recurring" type declaration:
Public Interface I(Of T As I(Of T))
Function Maker() As T
End Interface
Public Class C
Implements I(Of C)
Function Maker() As C Implements I(Of C).Maker
Return New C
End Function
End Class
Sub Main
Dim First As I(Of C) = New C
Dim Second As C = First.Maker
End Sub
As Steven says, this still doesn't force the declaring type to use itself as T, but at least now T definitely implements I.
If I have a class called A and a class called B, if B inherits A that means A is the super class and B is the subclass. I have been asked to describe why class A is not an abstract class but as i see it class A is an abstract class A, as it has been created for Class B to use in the future, is it something to do with Class B not being able to access the fields in Class A as although they are private by default?
Class A looks something like this
Public Class A
StartDate As Date
Men As Integer
Place As String
Public Sub New()
StartDate = Today
Men = 0
Place = ""
End Sub
End Class
Class B Looks like this
Public Class B inherits Class A
Grade As ExamGrade
Public Sub New()
MyBase.New
StartDate = Today
Men = 0
Place = ""
Grade = 'Easy'
End Sub
Public Function setGrade(grade As String)
ExamGrade = grade
End Function
End Class
In order to be abstract, class A must have the MustInherit keyword.
Abstract (MustInherit) means that this class serves as base class only and cannot be instantiated with New. It also allows you to declare abstract (MustInherit) members with no implementation, i.e. no method body. The inheriting classes then must override the abstract members and provide an implementation unless they are abstract themselves (where a third level of deriving classes would then provide an implementation).
Note that you are allowed to call an abstract member. At runtime the implementation of the actual implementing class will be called.
See: MustInherit (Visual Basic)
Members are private if not specified otherwise. Specify them to be Protected to allow descendant classes to see them or Public to allow "everybody" to see them.
See: Access Levels in Visual Basic
Public MustInherit ClassA
Protected StartDate As Date
Protected Men As Integer
Protected Place As String
Public Sub New()
StartDate = Today
Men = 0
Place = ""
End Sub
Public MustOverride Sub Print()
End Class
Public ClassB
Inherits ClassA
Public Grade As String
Public Sub New()
MyBase.New() 'This initializes StartDate, Men and Place
Grade = "Easy"
End Sub
Public Sub SetGrade(ByVal grade As String)
Me.Grade = grade
End Sub
Public Overrides Sub Print()
Console.WriteLine($"Grade = {Grade}")
End Sub
End Class
Now, you can use it like this
Sub Test(ByVal a As ClassA)
a.Print()
End Sub
You can call Test by passing it a ClassB object.
A is not abstract. Abstract means you cannot instantiate the class. It means you MUST inherit it.
Use the abstract keyword to make the class abstract. You can also make methods abstract as well.
If you want B to see certain methods in A, but not to anyone else, use protected keyword.
Sorry, VB uses the MustInherit and MustOverride keywords.
I have the following sample code in a VB.NET console application. It compiles and works, but feels like a hack. Is there a way to define EmptyChild so that it inherits from Intermediate(Of T As Class) without using the dummy EmptyClass?
Module Module1
Sub Main()
Dim Child1 = New RealChild()
Child1.Content = New RealClass()
Dim Child2 = New EmptyChild()
Console.WriteLine("RealChild says: " & Child1.Test)
Console.WriteLine("EmptyChild says: " & Child2.Test)
Console.ReadLine()
End Sub
Public Class EmptyClass
End Class
Public Class RealClass
Public Overrides Function ToString() As String
Return "This is the RealClass"
End Function
End Class
Public MustInherit Class Base(Of T As Class)
Private _content As T = Nothing
Public Property Content() As T
Get
Return _content
End Get
Set(ByVal value As T)
_content = value
End Set
End Property
Public Overridable Function Test() As String
If Me._content IsNot Nothing Then
Return Me._content.ToString
Else
Return "Content not initialized."
End If
End Function
End Class
Public MustInherit Class Intermediate(Of T As Class)
Inherits Base(Of T)
'some methods/properties here needed by Child classes
End Class
Public Class RealChild
Inherits Intermediate(Of RealClass)
'This class needs all functionality from Intermediate.
End Class
Public Class EmptyChild
Inherits Intermediate(Of EmptyClass)
'This class needs some functionality from Intermediate,
' but not the Content as T property.
Public Overrides Function Test() As String
Return "We don't care about Content property or Type T here."
End Function
End Class
End Module
The other way to do this would be to move the generic code out of the Base class and then create 2 Intermediate classes like this:
Public MustInherit Class Intermediate
Inherits Base
'some methods/properties here needed by Child classes
End Class
Public MustInherit Class Intermediate(Of T As Class)
Inherits Intermediate
'implement generic Content property here
End Class
Then RealChild would inherit from the generic Intermediate and EmptyChild would inherit from the non-generic Intermediate. My problem with that solution is that the Base class is in a separate assembly and I need to keep the code that handles the generic type in that assembly. And there is functionality in the Intermediate class that does not belong in the assembly with the Base class.
Yes, you need to specify a type parameter when you inherit, or your EmptyChild must be generic as well. But, you don't have to dummy up a EmptyClass - just use Object as your type parameter:
Public Class EmptyClass
Inherits Intermediate(Of Object)
End Class