Caching propertyinfo of abstract class - vb.net

I've been playing around with implementing an abstract base class that using reflection accomplishes SQL to Object mapping.
I did some benchmarks and decided I wanted to implement a caching strategy for the property info of the objects (to prevent future lookups on them). My first instinct was to try and implement something like this.
Public MustInherit Class BaseModel
Implements IFillable
Private Shared PropertyCache As List(Of PropertyInfo)
Sub New()
PropertyCache = New List(Of PropertyInfo)
For Each itm As PropertyInfo In Me.GetType().GetProperties
PropertyCache.Add(itm)
Next
End Sub
End Class
but then I realized that this would obviously not work because it would get overridden on subsequent object instantiations.
So now Im stuck, how can you implement an abstract class that caches its reflection "metadata"?
EDIT:
This is the best (workaround to my problem) I can come up with, Im hoping someone can suggest something better?
Public MustInherit Class BaseModel
Implements IFillable
Private Shared ReadOnly PropertyCache As New Dictionary(Of String, PropertyInfo)
Sub New()
Dim typeName As String = Me.GetType.ToString
For Each itm As PropertyInfo In Me.GetType().GetProperties
Dim lookupKey As String = String.Format("{0}_{1}", typeName, itm.Name)
If Not PropertyCache.ContainsKey(lookupKey) Then
PropertyCache.Add(lookupKey, itm)
End If
Next
End Sub
End Class

If you place the code in Shared Sub New instead it should only execute once.
http://msdn.microsoft.com/en-us/library/aa711965(v=vs.71).aspx

Related

Custom typed, non-generic, read-only, fixed-sized collection class in VB.Net?

I'm looking for suggestions on how to create a custom collection class in VB.Net, to contain instances of a custom object class. There is so much information on the topic that I'm not sure which direction to go in, and custom collections are new to me.
The collection needs are as follows:
collection should be read-only, it and its objects cannot be modified.
collection will always be a fixed size.
because of above two items, add, remove, count, clear, etc aren't needed.
will create & manage all object instances itself at instantiation.
should have a default property like "Item". (?)
should be enumerable, so For-Each can be used on it.
Here is a simplified outline of what I've pieced together so far:
Class Bay
Private ID As Integer
Private p_String As String
Private p_Aisle As Integer
...etc...
...getters, setters, & subs...
End Class
Class Bays
Inherits ...something...
Implements ....somethingelse... (?)
Public ReadOnly MyCollection(5094) as SomeCollectionType (Of Bay)
Private LastUpdate As Date
Private SystemStatus as Integer
Public Sub New()
...instantiate all objects in collection...
End Sub
...properties...
End Class
This is the sort of thing you can do:
Public Class Thing
'...
End Class
Public Class ReadOnlyThingCollection
Inherits ReadOnlyCollection(Of Thing)
Public Sub New()
MyBase.New(GetItems())
End Sub
Private Shared Function GetItems() As IList(Of Thing)
'Generate items as appropriate.
Return {New Thing, New Thing, New Thing}
End Function
End Class

Setting Up These Types While Keeping It Properly Structured

I'm completely stuck in a situation and I have no idea on where to go from here. I'm creating a very large project, so my goal is to keep the code itself as clean as possible and keeping as many hacks as possible out of the mix.
Here is the situation.
I have a class called Woo_Type, it is the parent of my many derived classes.
Public MustInherit Class Woo_Type
Private Shared TypeList As New Dictionary(Of String, Woo_Type)
Public MustOverride Sub SetValue(ByVal val As Object)
Public MustOverride Function GetValue() As Object
Public Shared Function GetTypeFromName(ByVal name As String) As Woo_Type
Return TypeList(name)
End Function
Public Shared Sub AddType(ByVal name As String, ByVal def As Woo_Type)
TypeList.Add(name, def)
End Sub
End Class
I have many classes that Inherit from Woo_Type that have similar structures to this:
Public Class Woo_tpInt
Inherits Woo_Type
Private value As Integer = 0
Public Overrides Function GetValue() As Object
Return value
End Function
Public Overrides Sub SetValue(val As Object)
value = val
End Sub
End Class
I want to be able to do things like:
Woo_Type.GetTypeFromName("int")
And have it return something like the class or something...
At this point I'm really confused as to what I want and I didn't know if anybody had any suggestions. To make sure that GetTypeFromName worked correctly, I had in an Initializer sub the following:
Public Sub InitializeTypes()
Woo_Type.AddType("int", Woo_tpInt)
Woo_Type.AddType("String", Woo_tpInt)
End Sub
But I quickly realized that-that obviously doesn't work either.
So this may seem confusing but I'm basically wondering how to better structure this so that everything works...
What do you want to do with the result? Are you sure you don't simply need generics?
Public Class WooType(Of T)
Public Property Value As T
End Class
Public Class Test
Public Sub Foo()
Dim int As New WooType(Of Integer)
int.Value = 42
Dim str As New WooType(Of String)
str.Value = "Forty-Two"
End Sub
End Class
If what you want to do is get the type itself (as opposed to an object), I would recommend using reflection rather than trying to reinvent the wheel. For instance, to get the Woo_tpInt type, you could do this:
Dim a As Assembly = Assembly.GetExecutingAssembly()
Dim t As Type = a.GetType("WindowsApplication1.Woo_tpInt") ' Change WindowsApplication1 to whatever your namespace is
If you want to use a shorter name like "int" to mean "WindowsApplication1.Woo_tpInt", you could create a dictionary to store the translation table, for instance:
Dim typeNames As New Dictionary(Of String, String)
typeNames.Add("int", GetType(Woo_tpInt).FullName)
Dim a As Assembly = Assembly.GetExecutingAssembly()
Dim t As Type = a.GetType(typeNames("int"))

VB Polymorphism Constructors Default and Properties. Similar Class to Listbox

I've been banging my head against a wall for sometime on this one.
I'm trying to create a class for storing data on People with another class to store their Bank Transactions.
Ideally, this all be hidden away and leave only simple statments, declarations and functions available to the programmer. These will include:
Dim Clients As New ClientList
Clients.Count 'readonly integer
Clients.Add("S")
Clients.Refresh()
Clients(n).Remove()
Clients(n).Transaction.Add()
Clients(n).Transaction(n).Remove()
I know this is possible as these exist in the Listbox Class though can't figure out how it's done.
Any help would be appreciated.
Thanks in advance!
Create a Transaction and a Client class
Public Class Transaction
'TODO: Implement Transaction
End Class
Public Class Client
Public ReadOnly Transactions As List(Of Transaction) = New List(Of Transaction)
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
Public Name As String
End Class
Create a ClientList class
Public Class ClientList
Inherits List(Of Client)
Public Overloads Sub Add(ByVal name As String)
Add(New Client(name))
End Sub
Public Sub Refresh()
' Do what ever you want Refresh to do
End Sub
End Class
You can then use the client list like this
Dim clients As New ClientList
clients.Add("S")
' Or
clients.Add(New Client("T"))
Dim n As Integer = clients.Count
Dim m As Integer = clients(0).Transactions.Count
clients.Refresh()
clients.RemoveAt(5)
clients(n - 1).Transactions.Add(New Transaction())
clients(n - 1).Transactions.RemoveAt(2)
Dim name As String = clients(0).Name
Dim client As Client = clients(0)
Use the generic List(Of T) class, specialized to hold your Client objects. It already provides all of the methods you want without your having to write a single line of code!
So you would first write a Client class that contained all of the properties (data) and methods (actions) relating to a "client":
Public Class Client
Public Property Name As String
Public Property AmountOwned As Decimal
Public Sub Bill()
BillingManager.BillClient(Me)
End Sub
' ... etc.
End Class
Then, you would create the List(Of T) to hold all of your instances of the Client class:
Dim clients As New System.Collections.Generic.List(Of Client)
If, for whatever reason, you needed to specialize the behavior of the Add, Remove, etc. methods provided by the collection class, or add additional methods, you would need to change strategies slightly. Instead of using List(Of T), you would inherit from Collection(Of T) and create a custom collection class like so:
Public Class ClientCollection
Inherits System.Collections.ObjectModel.Collection(Of T)
' ... customize as desired ...
End Class
The WinForms ListBox class doesn't do it exactly like this because it was written before generics were introduced to the framework. But since they're here now, and you should always use them when possible, you can completely ignore how WinForms does things.

WCF serializing objects with inheritance

Here's what I am trying to do. I have a WCF restful service, and I need to serialize multiple objects that inherit from the same class.
There is nothing in any of the base classes that needs to be serialized.
Here is a minimal demo that shows what I want to get to work:
<DataContract()>
Public Class BaseObj
<DataMember()>
Public ID As Integer
Public Sub New(ByVal idval As Integer)
ID = idval
End Sub
End Class
<DataContract()>
Public Class TestObj1
Inherits BaseObj
Public Sub New(ByVal id As Integer)
MyBase.New(id)
End Sub
End Class
' Different from TestObj1 in real life
<DataContract()>
Public Class TestObj2
Inherits BaseObj
Public Sub New(ByVal id As Integer)
MyBase.New(id)
End Sub
End Class
And here's the code that uses it:
<ServiceContract()>
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerCall)>
Public Class Service1
<WebGet(ResponseFormat:=WebMessageFormat.Json, UriTemplate:="Test?reqReportID={reqReportID}")>
Public Function GetCollection(ByVal reqReportID As Integer) As List(Of BaseObj)
Dim myObjs As New List(Of BaseObj)
myObjs.Add(New TestObj1(20))
myObjs.Add(New TestObj2(20))
Return myObjs
End Function
End Class
If I declare the List to be a list of TestObj1 instead, everything works.
Am I missing some crucial concept here?
EDIT:
The problem gains a new level of confusion by looking at this code:
<WebGet(ResponseFormat:=WebMessageFormat.Json, UriTemplate:="Test?reqReportID={reqReportID}")>
Public Function GetCollection(ByVal reqReportID As Integer) As BaseObj()
Dim myObjs As New List(Of BaseObj)
myObjs.Add(New TestObj1(20))
myObjs.Add(New TestObj2(20))
' This guy works. Yields correct result of [{"ID":20},{"ID":20}] )
Dim testStr As String = New JavaScriptSerializer().Serialize(myObjs.ToArray())
' But this guy still has problems...
Return myObjs.ToArray()
End Function
What you are missing is a [KnownType] attribute.
WCF requires a way of knowing all possible types so that it could publish the WSDL.
Have a look here.
UPDATE
The problem is that List<T> is not covariant.
Use IEnumerable<T> instead.

Similar classes with different signatures

I have two classes:
Public Class Subscribing
Private _subscribingObjects As IList(Of String)
Public Sub Add(ByVal obj As SubscribeObject)
'...code...'
End Sub
Public Sub Remove(ByVal index As Integer)
'...code...'
End Sub
End Class
Public Class Providing
Private _providingObjects As IList(Of String)
Public Sub Add(ByVal obj As ProvideObject)
'...code...'
End Sub
Public Sub Remove(ByVal index As Integer)
'...code...'
End Sub
End Class
Is there a more elegant way to add do this? One class would suffice, but since the Add methods have different arguments, then one really wouldn't work.
Any help would be appreciated.
this?
Public Class SubscribingProviding(Of t)
Private _subscribingObjects As IList(Of String)
Public Sub Add(ByVal obj As t)
'...code...'
End Sub
Public Sub Remove(ByVal index As Integer)
'...code...'
End Sub
End Class
Your add functions should be fine. As long as you have different variable types being passed in you can have the function names be the same. Your remove Subs will not be allowed in the same class because it is using the same parameter Integer.
Eh.. probably not. They are different enough that you cant even Interface them.
I personally wouldn't mix the two responsibilities (of subscribing and providing) in one class. The classes themselves can easily be simplified by just inheriting from List(Of T)
Public Class Subscribing
Inherits List(Of SubscribeObject)
End Class
Public Class Providing
Inherits List(Of ProvideObject)
End Class
If you really want to get down to one class and make sure that it can only accept SubscribeObject and ProvideObject respectively, implement a common interface in both SubscribeObject and ProvideObject. Then create a generic class that accepts the interface:
' Common interface '
Public Interface ISubscribeProvideObject
End Interface
' SubscribeObject and ProvideObject both implementing the common interface '
Public Class SubscribeObject
Implements ISubscribeProvideObject
'...'
End Class
Public Class ProvideObject
Implements ISubscribeProvideObject
'...'
End Class
' Generic class accepting both types '
Public Class SubscribingProviding(Of T As ISubscribeProvideObject)
Inherits List(Of T)
'... Add() and Remove() methods only needed if custom logic applies ...'
End Class