I have a little Problem:
I have a method that parses an incoming string for certain values, if a value is found, a new class is instantiated. The class name is identical to the parsed string. At the moment, my code looks like this:
Public Class Test1
End Class
Public Class Important
End Class
Public Class DoWork
Public Sub DoWork(incoming as String)
Select case incoming
case "Test1"
dim myobj as new Test1
Case "Important"
dim myobj as new Important
End Select
End Sub
End Class
I do not like the string literals like "Test1" - i could store them in a constant, but if the class names change, they have to be changed too. Is there a way to replace the literals with the Name of class?
I know that me.gettype produces the result for instantiated objects, but what about the simple name for a class, which is no object at this moment?
If your string is in correct format you can use Type.GetType(string) method to retrieve type. Then you can use Activator class to create instance if you have default constructor on that type.
Rafal's answer is good if you're stuck with the current situation, with the incoming string parameter. But it's still a bit fragile. What if the incoming parameter changes? What if you want to restructure your code, moving some classes to different namespaces or assemblies? What if those strings change - do you now have to rename your classes and recompile? You don't see the magic strings explicitly now, but they're still there.
So ask yourself - where are those strings coming from? Are they generated internally by your code? If so, you might want to generate, instead of strings, an Enum value that corresponds to the class to be instantiated. If they're external strings that you map to your classes, consider having explicit mapping (in a configuration file, for instance) that map String->Type. It's a bit more cumbersome, but a lot more flexible.
Related
I have a class that I would like to extend by defining a new class that contains the first class as a public property, as well as additional added properties. However, the class that I'm extending has multiple derived types, which should be treated the same in the extension class.
Below is an example of what I am trying to do:
Public Class ClassA
End Class
Public Class ClassB
Inherits ClassA
End Class
Public Class ClassC
Inherits ClassA
End Class
Public Class BaseExtended
Public Property Foo As ClassA
Public Property ExtendedMetaData1 As Double
Public Property ExtendedMetaData12 As Integer
End Class
Public Class DerivedExtendedB
Inherits BaseExtended
Public Property Foo As ClassB
End Class
Public Class DerivedExtendedC
Inherits BaseExtended
Public Property Foo As ClassC
End Class
The code that uses an instance of any of the 'extended' classes would then need use that instance appropriately depending on it's type. There would be many cases where the property 'Foo' needs to be accessed and modified outside of the class that it belongs to.
If I were to implement something like what I have shown above, that would require that I first cast it to the required type before accessing or modifying it. Ideally I would like to do that inside the 'DerivedExtended' class; The alternative, I think, would be to duplicate code to cast that property would [hundreds of times] in the client code.
Private Sub ClientUsesObject(bar As BaseExtended)
' Perform a task that is agnostic Foo type
' Would not require that Foo be cast to any specific type
If bar.GetType() Is GetType(DerivedExtendedB) Then
Dim barCast As DerivedExtendedB = DirectCast(bar, DerivedExtendedB)
' Perform task that requires Foo to be of type ClassB
ElseIf bar.GetType() Is GetType(DerivedExtendedC) Then
Dim barCast As DerivedExtendedC = DirectCast(bar, DerivedExtendedC)
' Perform task that requires Foo to be of type ClassC
End If
End Sub
What I'm looking for is advice outlining or describing a design pattern that can handle this situation. I've searched for quite a while, and have not been able to find any examples that solve this problem.
I realize that this may be somewhat of an "XY" problem. I'm working with existing code that simply assumes all instances are of the same derived type (when in fact some instances are of the other derived type). As such, the existing code does not work. To me what I've tried to outline above seems like the most straightforward path, but I'm open to alternative if this is just the wrong approach.
This pattern of type covariance in derived classes is the canonical reason for what is called in C++ the "Curiously Recurring Template Pattern" and has been called in .NET the "Curiously Recurring Generic Pattern." I believe it's also sometimes referred to as "F-Bounded Polymorphism" (not a computer scientist, so I might have the reference wrong).
You can write a base class like this:
Public Class Base(Of TDerived As Base)
Public Overridable Property foo As TDerived
End Class
And then use it like this:
Public Class MyDerived
Inherits Base(Of MyDerived)
End Class
Then, the derived class has a property foo whose type is MyDerived. No casting required by clients.
However, this has some limitations. It works best when you don't need to switch back and forth between derived and base. There is no one Base, so you can't declare instances of it. If you want to be able to declare something as Base, then you end up needing to fall back on a non-generic base class. This will still work well for certain usage patterns where you don't need to convert from base to derived, but otherwise you run right back into the casting problems you are trying to avoid.
Eric Lippert has written a bit about this pattern. He's always interesting to read, so I'd recommend looking up his commentary.
Another alternative to consider, if the generic approach doesn't work for you, is code generation. You can use T4 templates to process a compact description of what your code should be, and generate the code files from them. A long list of casts is less tedious if you only write the machinery to generate it, you don't write them all out explicitly.
I need to be able to change the value the variable "timeMins" at runtime in the JSON container class below. But, the only way that VB.Net allows me to do this is to declare "timeMins" as a Constant - However, constants cannot be changed at runtime as far as I know in VB.net.
Below is what I have so far...It compiles and runs, but does not do what I need it to do.
Const timeMins As String = "15"
Public Class JSON_Container_Real_Time
<JsonProperty(PropertyName:="Meta Data")>
Private Meta As MetaData
<JsonProperty(PropertyName:="Time Series (" + timeMins + "min)")>
Public Time_Series_Daily As Dictionary(Of String, StockInfo)
End Class
In its current state what you're trying to do is not possible. At namespace level you're only allowed to declare types and constants, so you would need to move the variable declaration inside your class in order to be able to make it a non-constant. However, this means that you cannot use it in the JsonProperty attribute, because attributes require constant values only.
You would have to look for another solution to serialize/deserialize you class.
I need to create a property in a class that will give the programmer a list of values to choose from. I have done this in the past using the enums type.
Public Enum FileType
Sales
SalesOldType
End Enum
Public Property ServiceID() As enFileType
Get
Return m_enFileType
End Get
Set(ByVal value As enenFileType)
m_enFileType = value
End Set
End Property
The problem is I would like to populate the list of values on init of the class based on SQL table values. From what I have read it is not possible to create the enums on the fly since they are basically constants.
Is there a way I can accomplish my goal possibly using list or dictionary types?
OR any other method that may work.
I don't know if this will answer your question, but its just my opinion on the matter. I like enums, mostly because they are convenient for me, the programmer. This is just because when I am writing code, using and enum over a constant value gives me not only auto-complete when typing, but also the the compile time error checking that makes sure I can only give valid enum values. However, enums just don't work for run-time defined values, since, like you say, there are compile time defined constants.
Typically, when I use flexible values that are load from an SQL Table like in your example, I'll just use string values. So I would just store Sales and SalesOldType in the table and use them for the value of FileType. I usually use strings and not integers, just because strings are human readable if I'm looking at data tables while debugging something.
Now, you can do a bit of a hybrid, allowing the values to be stored and come from the table, but defining commonly used values as constants in code, sorta like this:
Public Class FileTypeConstants
public const Sales = "Sales"
public const SalesOldType = "SalesOldType"
End Class
That way you can make sure when coding with common values, a small string typo in one spot doesn't cause a bug in your program.
Also, as a side note, I write code for and application that is deployed internally to our company via click-once deployment, so for seldom added values, I will still use an enum because its extremely easy to add a value and push out an update. So the question of using and enum versus database values can be one of how easy it is to get updates to your users. If you seldom update, database values are probably best, if you update often and the updates are not done by users, then enums can still work just as well.
Hope some of that helps you!
If the values aren't going to change after the code is compiled, then it sounds like the best option is to simply auto-generate the code. For instance, you could write a simple application that does something like this:
Public Shared Sub Main()
Dim builder As New StringBuilder()
builder.AppendLine("' Auto-generated code. Don't touch!! Any changes will be automatically overwritten.")
builder.AppendLine("Public Enum FileType")
For Each pair As KeyValuePair(Of String, Integer) In GetFileTypesFromDb()
builder.AppendLine(String.Format(" {0} = {1}", pair.Key, pair.Value))
End For
builder.AppendLine("End Enum")
File.WriteAllText("FileTypes.vb", builder.ToString())
End Sub
Public Function GetFileTypesFromDb() As Dictionary(Of String, Integer)
'...
End Function
Then, you could add that application as a pre-build step in your project so that it automatically runs each time you compile your main application.
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
i want to implement Hashmap in symbian
which takes two values
is there any body who have implement it
there is class RHashMap,RHashTable but i want to pass descrpter and value
or
else is there any class other solution for this
thanks in advance
I think the documentation doesn't make clear the fact that you should probably have a class that contains an integer and a descriptor.
The THashFunction32 that you need to implement takes one instance of your class and return it's integer member.
The TIdentityRelation that you need to implement takes two instances of your class and compares the integer members.
When you insert an instance of your class into the RHashMap, both the integer and the descriptor members need to have meaningful values.
When you want to retrieve a descriptor from your RHashMap, you create and instance of your class but only set the integer member value. Use that object as a parameter to RHashMap::Find() and it will return the instance of your class that contains the descriptor you were looking for.
RHashMap is a templated type. You can use whatever classes you requires as follows:
RhashMap<TInt,TPtr> map;
map.Insert(myInt,myDes);
...
myDes = map.FindL(myInt);
TInt error = map.Remove(myInt);
User::LeaveIfError(error);
map.Close();
Edit: If you wanted a single key to point to two things, then just encapsulate those two things in a single object.