I have a Base Class, called primitive Graphics. derived from this class are several different types of graphics, squares, rectangles, lines, etc.
I am storing those graphics in an object that inherits collectionbase. This causes a problem because I cannot access any of the members in the derived class when they are added to the collection.
Here is the default property for my primitivecollection class
Public Class PrimitiveCollection
Inherits CollectionBase
''' <summary>
''' Get or set a primitive object by index
''' </summary>
Default Public Property Item(ByVal index As Integer) As Primitive
Get
Return DirectCast(List(index), Primitive)
End Get
Set(ByVal value As Primitive)
List(index) = value
End Set
End Property
My current workaround is to just put all of the public members in the base class, however this is starting to look ugly as I add more derived classes that need members available to the derived class only
Your question is about inheritance and interfaces. The following is my opinion
Each Primitive should implement an interface, IPrimitive. Every Primitive in the Collection implements IPrimitive and the only things in IPrimitive are the things that apply to all types of IPrimitives. For example: Draw()
So when working with your collection, you have a collection of drawable objects. If you intend to work with a collection as a collection of just Rectangles, you should use a List<Rectangle> rather than a collection of Primitives.
Putting more properties onto the base class (or IPrimitive) is a bad idea, because they won't make sense for all objects. Width could work for a Rectangle, but gets shady when you're working with a Trapezoid or Triangle. Instead the Commonality should be as little as is necessary to work with the objects as a collection. And when you need to work with the objects as their derived classes, you should be referencing them without using the collection.
If you're storing multiple types of object within a single collection, then you'll need to cast between them to access type-specific members, yes.
If you're actually storing multiple objects of a single derived type in a collection, you should look at using generics instead, so that the collection remains strongly typed (i.e. the compiler knows that the collection only contains instances of the derived type).
You will need to cast the instances in the collection to the derived type in order to access their specific members.
I will add an example:
PrimitiveCollection primitives = GetPrimitives() ' this gets a mixture of types
If GetType(PrimitiveRectangle) = primitives[0].GetType() Then
' this is a PrimitiveRectangle object
PrimitiveRectangle rect = CType(primitives[0], PrimitiveRectangle)
' now you can access specialized members through rect
End If
I didn't use VB.NET in a couple of years, so there may be issues with the syntax...
Related
I know what classes are about, but for better understanding I need a use case. Recently I discovered the construct of data classes. I get the idea behind normal classes, but I cannot imagine a real use case for data classes.
When should I use a data class and when I use a "normal" class? For all I know, all classes keep data.
Can you provide a good example that distinguishes data classes from non-data classes?
A data class is used to store data. It's lighter than a normal class, and can be compared to an array with key/value (dictionary, hash, etc.), but represented as an object with fixed attributes. In kotlin, according to the documentation, that adds those attributes to the class:
equals()/hashCode() pair
toString() of the form "User(name=John, age=42)"
componentN() functions corresponding to the properties in their order of declaration.
copy() function
Also it has a different behavior during class inheritence :
If there are explicit implementations of equals(), hashCode(), or toString() in the data class body or final implementations in a
superclass, then these functions are not generated, and the existing
implementations are used.
If a supertype has componentN() functions that are open and return compatible types, the corresponding functions are generated for the
data class and override those of the supertype. If the functions of
the supertype cannot be overridden due to incompatible signatures or
due to their being final, an error is reported.
Providing explicit implementations for the componentN() and copy() functions is not allowed.
So in kotlin, if you want to describe an object (a data) then you may use a dataclass, but if you're creating a complex application and your class needs to have special behavior in the constructor, with inheritence or abstraction, then you should use a normal class.
I do not know Kotlin, but in Python, a dataclass can be seen as a structured dict. When you want to use a dict to store an object which has always the same attributes, then you should not put it in a dict but use a Dataclass.
The advantage with a normal class is that you don't need to declare the __init__ method, as it is "automatic" (inherited).
Example :
This is a normal class
class Apple:
def __init__(size:int, color:str, sweet:bool=True):
self.size = size
self.color = color
self.sweet = sweet
Same class as a dataclass
from dataclasses import dataclass
#dataclass
class Apple:
size: int
color: str
sweet: bool = True
Then the advantage compared to a dict is that you are sure of what attribute it has. Also it can contains methods.
The advantage over to a normal class is that it is simpler to declare and make the code lighter. We can see that the attributes keywords (e.g size) are repeated 3 times in a normal class, but appear only once in a dataclass.
The advantage of normal class also is that you can personalize the __init__ method, (in a dataclass also, but then you lose it's main advantage I think) example:
# You need only 2 variable to initialize your class
class Apple:
def __init__(size:int, color:str):
self.size = size
self.color = color
# But you get much more info from those two.
self.sweet = True if color == 'red' else False
self.weight = self.__compute_weight()
self.price = self.weight * PRICE_PER_GRAM
def __compute_weight(self):
# ...
return (self.size**2)*10 # That's a random example
Abstractly, a data class is a pure, inert information record that doesn’t require any special handling when copied or passed around, and it represents nothing more than what is contained in its fields; it has no identity of its own. A typical example is a point in 3D space:
data class Point3D(
val x: Double,
val y: Double,
val z: Double
)
As long as the values are valid, an instance of a data class is entirely interchangeable with its fields, and it can be put apart or rematerialized at will. Often there is even little use for encapsulation: users of the data class can just access the instance’s fields directly. The Kotlin language provides a number of convenience features when data classes are declared as such in your code, which are described in the documentation. Those are useful when for example building more complex data structures employing data classes: you can for example have a hashmap assign values to particular points in space, and then be able to look up the value using a newly-constructed Point3D.
val map = HashMap<Point3D, String>()
map.set(Point3D(3, 4, 5), "point of interest")
println(map.get(Point3D(3, 4, 5))) // prints "point of interest"
For an example of a class that is not a data class, take FileReader. Underneath, this class probably keeps some kind of file handle in a private field, which you can assume to be an integer (as it actually is on at least some platforms). But you cannot expect to store this integer in a database, have another process read that same integer from the database, reconstruct a FileReader from it and expect it to work. Passing file handles between processes requires more ceremony than that, if it is even possible on a given platform. That property makes FileReader not a data class. Many examples of non-data classes will be of this kind: any class whose instances represent transient, local resources like a network connection, a position within a file or a running process, cannot be a data class. Likewise, any class where different instances should not be considered equal even if they contain the same information is not a data class either.
From the comments, it sounds like your question is really about why non-data classes exist in Kotlin and why you would ever choose not to make a data class. Here are some reasons.
Data classes are a lot more restrictive than a regular class:
They have to have a primary constructor, and every parameter of the primary constructor has to be a property.
They cannot have an empty primary constructor.
They cannot be open so they cannot be subclassed.
Here are other reasons:
Sometimes you don't want a class to have a copy function. If a class holds onto some heavy state that is expensive to copy, maybe it shouldn't advertise that it should be copied by presenting a copy function.
Sometimes you want to use an instance of a class in a Set or as Map keys without two different instances being considered as equivalent just because their properties have the same values.
The features of data classes are useful specifically for simple data holders, so the drawbacks are often something you want to avoid.
I have a weird issue. I want to implement an extension to List with a function to merge another list into it excluding the duplicate values:
<Extension()>
Public Sub AddUnique(Of T)(ByVal self As IList(Of T), ByVal items As IEnumerable(Of T))
For Each item In items
If Not self.Contains(item) Then self.Add(item)
Next
End Sub
Now, I have a class that I'll be creating objects from, and adding them to a list:
Class DocInfo
Public Property title As String
Public Property fullPath As String
Sub New(title As String, fullPath As String)
Me.title = title
Me.fullPath = fullPath
End Sub
End Class
Then, I have a list as a global variable:
Public docsInfo As New List(Of DocInfo)
And then I have a button handler that adds new items to that list:
Private Sub AddToList_Button_Click(sender As Object, e As RoutedEventArgs)
Dim candidateItems As New List(Of DocInfo)
For Each doc In selectedDocs
candidateItems.Add(New DocInfo(doc.GetTitle(), doc.GetPathName()))
Next
docsInfo.AddUnique(candidateItems)
End Sub
(The doc and selectedDocs variables are outside of the scope of this question.)
Now, the important bit - GetTitle() and GetPathName() return the same strings on every button click (I have the same docs selected between clicks). Meaning that DocInfo objects that are added to the candidateItems, and then added to docsInfo, are identical. Nevertheless, the extension function AddUnique fails, resulting in duplicates in the list.
Puzzled, I ran GetHashCode() on these duplicate DocsInfo class objects:
For Each docInfo In docsInfo
Console.WriteLine(docInfo.title)
Console.WriteLine(docInfo.fullPath)
Console.WriteLine(docInfo.GetHashCode())
Next
And this is the output:
Assem1^Test assembly.SLDASM
C:\Users\Justinas\AppData\Local\Temp\swx5396\VC~~\Test assembly\Assem1^Test assembly.SLDASM
7759225
Assem1^Test assembly.SLDASM
C:\Users\Justinas\AppData\Local\Temp\swx5396\VC~~\Test assembly\Assem1^Test assembly.SLDASM
14797678
With each button click, I am getting identical DocsInfo objects (title and fullPath properties have the same values), yet their hashes are different every time, and every comparison I can think of, fails to acknowledge that these objects are for all intents and purposes idendical.
Why is this happening? And how can I fix the AddUnique extension function to work as intended?
This behavior is because of the difference in .NET between "Reference" types and "Value" types. The fundamental philosophy of these is that for "Reference" types, object identity takes precedence over contents (that is, two different object instances with the same contents are still considered distinct), while for "Value" types, the contents are the only thing that matters.
In VB, Class denotes a reference type while Structure denotes a value type. Their respective behaviors are what you would expect, then: by default, Equals on a Class is equivalent to ReferenceEquals, checking to see if the references are the same, and GetHashCode returns a value based on the object identity. Equals on a Structure does member-wise value equality, and GetHashCode returns a value based on the hash codes of the members.
There are a couple of different options for overriding the default behavior, with differing impacts and levels of intrusiveness.
You can change Class to Structure. If you do so, I would strongly recommend to eliminate any mutable behavior on them (i.e. make all fields and properties ReadOnly), because mutable Structures can be extremely hard to reason about correctly. If you really do have immutable data, though, this is the easiest to maintain because .NET will already do what you want, you don't have to maintain your own Equals or GetHashCode override.
You can override GetHashCode and Equals on your Class to act like the Structure versions. This won't change anything else about your class, but it will make it act like a value type for the purposes of containers and sequences. If you're worried about maintenance, an alternative would be to do something reflection-based, though this shouldn't be used for anything that will be high-throughput because reflection is generally not particularly performant.
I believe the hashing and ordering containers take optional constructor parameters that will let you provide a class for overriding the behavior of the contents without altering the Class itself. You could do something like this. I'd recommend to look at the MSDN docs for HashSet.
Is there any way to get the value of an objects' private attribute without a getter. Modifying the class is not permitted in any shape or form.
Please find below an example class with a private attribute.
CLASS counter DEFINITION.
PUBLIC SECTION.
METHODS: set IMPORTING value(set_value) TYPE i.
PRIVATE SECTION.
DATA count TYPE i.
ENDCLASS. "counter DEFINITION
CLASS counter IMPLEMENTATION.
METHOD set.
count = set_value.
ENDMETHOD. "set
ENDCLASS. "counter IMPLEMENTATION
How can I get the value of count? Inheriting from counter will not work because count is private, not protected.
Unfortunately not, I have tried this myself in many different ways none of which work:
Having a standard super class - the super class cannot access the
private attributes of subclasses dynamically
Making a subclass will never work since it can only access protected
Attempting to use the unit test framework doesn't work. I tried to
call the kernel modules that allow access to private data but to no
avail.
You are basically flat out of luck. There is one obscure option though depending on the class you are trying to access. Some classes have interfaces specified as friends and if you implement that interface you can access their private data (the ALV on 7.20 is like this) but unfortunately this will only work in a few limited cases.
Runtime type services are the abap's equivalent of reflection.
They allow You nearly to scan every object, and mostly even modify it at runtime. As far as i know, the visibility of attributes does not matter. But be careful.
And read about the various classes, because there are many, each specified to work on a special type of dataopbject ( structs, objects, etc)
http://wiki.scn.sap.com/wiki/pages/viewpage.action?pageId=42965
You could make a sub class, re-implement the setter and set a second variable, then call the parent method. Be aware of the ramifications of having two variables holding the same stuff... Please see vwegert's comments and see if you really want to because it's generally not a great idea and it breaks the rules of OO.
CLASS counter_sub DEFINITION INHERITING FROM counter.
PUBLIC SECTION.
data count2 type i read-only.
METHODS: set REDEFINITION.
ENDCLASS. "counter_sub DEFINITION
CLASS counter_sub IMPLEMENTATION.
METHOD set.
count2 = set_value.
super->set( set_value ).
ENDMETHOD. "set
ENDCLASS. "counter_sub IMPLEMENTATION
I'm working with vb.net, wcf, wpf and I'm refactoring working code with the hope of being able to reduce some amount of redundancy. I have a bunch of methods that get called in several places throughout the code that only have a slight variation from each other and I would like to replace them with a single method instead.
Specifically, each of the redundant methods process an 1-d array that contain different objects I have created. There are several of these different object types each with different signatures but they have all have a "name" and "Id" property. (Also these objects don't have a shared base class but I could add that if needed.) Each of the redundant methods deal with a different one of the object types.
To refactor the code I would like to pass any of the different object arrays to a single new method that could access the "name" and "id" properties. I'm trying to write this new method in a fashion that wouldn't require me to update it if I created more objects down the road.
I've done some reading on Delegates and Generic Classes but I can't really figure out how this fits in. It would almost be as if I wanted to create a generic class that could handle each of my object types but then somehow also access the "name" and "id" propeties of the different object types.
Any help you can provide would be appretiated. Also, please keep in mind this project is written in VB.net.
Thanks
Mike
It sounds like having your object implement a common interface or have a shared base class would be best. Interfaces give you the most flexibility down the road if you ever need to pass a class to this method that must derive from some other class that does not implement the interface. However, a base class that implements the interface may also be useful just to reduce the duplicate declarations of these properties.
Public Interface IThingThatHasNameAndId 'good name not included
ReadOnly Property Name As String
ReadOnly Property Id As Integer
End Interface
Once you have the interface, you can then pass arrays of types implementing the interface as IEnumerable(Of IThingThatHasNameAndId) or make a generic method taking T() and constrain T to the interface.
Make a base class with the Name and ID properties, then you can make a method that takes in any class that derrives from that class.
Public Function TestFunction(Of t As YourBaseClass)(Byval obj As t) As Boolean
If obj.Name = "Some Name" AndAlso obj.ID = 1 Then
Return True
Else
Return False
End If
End Function
How do I get using reflection the most generic type from a shared constructor in the base class :
Public Class Foo()
Shared Sub New()
'Here we have code to get the type!
MethodBase.GetCurrentMethod().DeclaringType
End
End Class
Public Class Bar()
Inherits Foo
End Class
I expect the result to be Bar type and not the Foo. Is it possible?
First, it seems you want to find the most derived type (or the most specific type), not the most generic type -- which would mean rather the opposite (either, that generics are involved, or that the most general type is being sought).
While it may be possible to do this using reflection, your need for it might indicate that you have your class design wrong, or less than optimal.
First, constructors aren't virtual methods, so inside a constructor (IIRC), the Me object reference is of the type that contains this constructor.
What you could do is reflect over all of an assembly's types and find all those that are derived from Foo. You would then have to build a inheritance graph of these types and assign a number to each saying how far it is derived from Foo (number of inheritance levels). You could then check the Me object reference against all of the types you've identified (see if Me can be cast to each of them), and from that subset, choose the one type with the largest number of inheritance levels.
I hope that from this, you'll see that it's probably not worth the effort. It would be more interesting, and probably more helpful, to re-think why you need to do this, and if possible, find a way to avoid it.