From A Method With In The Class Return An Instance Of The Class As An Interface Type That The Class Implements - vb.net

what I'm trying to archive with the code below is to have the GetInstance generic function take in an interface type that SystemVars implements (say IAuthentication) then create an instance of SystemVars and return it as interface type T.
The problem I an having is that no matter what casting method I try I can't find a way to return the new instance of SystemVars as T. The line in the GetInstance method Return <CastingFunction>(New SystemVars,T) always fails to compile with the error message saying Value of type SystemVars cannot be converted to 'T'.
How do I return the instance of the class as the interface type that was passed into T?
Imports System.Drawing
Public Class SystemVars
Implements IAuthentication,
IAuthorization,
IApplicationStarting
Private Sub New()
End Sub
Public Shared Function GetInstance(Of T)() As T
Return DirectCast(New SystemVars, T)
End Function
Public ReadOnly Property Username As String _
Implements IAuthentication.Username,
IAuthorization.Username
Get
Return _userName
End Get
End Property
Public ReadOnly Property Rolls As List(Of String) _
Implements IAuthorization.Rolls
Get
Return _rolls
End Get
End Property
Public ReadOnly Property InstallationId As Guid _
Implements IAuthentication.InstallationId,
IApplicationStarting.InstallationId
Get
Return _installationId
End Get
End Property
Public ReadOnly Property MainWindowStartUpPlacement As Rectangle _
Implements IApplicationStarting.MainWindowStartUpPlacement
Get
Return _mainWindowStartUpPlacement
End Get
End Property
'........
Private Shared _userName As String
Private Shared _rolls As List(Of String)
Private Shared _installationId As Guid
Private Shared _mainWindowStartUpPlacement As Rectangle
End Class

You can make an otherwise illegal cast work by passing through Object.
Public Shared Function GetInstance(Of T)() As T
Return DirectCast(CObj(New SystemVars), T)
End Function
You will get a runtime error if the cast isn't possible; as noted in the comments, this strategy is chucking type safety out the window and basically telling the compiler, "Don't bother me, I know what I'm doing." The runtime will throw an InvalidCastException on failure if you don't test and throw yourself. You can test using Type.IsAssignableFrom if you want to create a more developer-friendly error message; there isn't much context available in the debugger at the point of failure, though it may be pretty obvious if you look up the call stack.
For just three interfaces, it might be better to do three separate specific functions rather than a generic version, especially considering that the functions are necessarily Shared (and thus can't themselves be part of an interface).
You might also consider a design that includes a Dependency Injection container. In this kind of design, there would be a configuration step that would associate the interfaces with SystemVars as the implementation, then the client would ask the container for an instance of the interface and receive a SystemVars object.
The rough way that the three options (the third being to cast the SystemVars object to the requested interface) would look in code is:
'Casting a received object to a requested interface
Dim asInterface = DirectCast(SystemVars.GetInstance(), IAuthorization)
'Using a custom casting function on SystemVars
Dim asInterface = SystemVars.GetInstance(Of IAuthorization)
'Using a DI container
'Behavior if the interface isn't supported depends on the container
Dim asInterface = container.GetInstance(Of IAuthorization)
Note that TryCast could be used instead of DirectCast, in which case the result would be Nothing if the interface isn't supported.

Related

How To Access A Shared Property Of A Class Passed As A Type Parameter

I'm trying to access a shared property of a class passed as a parameter to a type-parametrised procedure. The reason why I'm doing this is so I can embed the various API call endpoints (among other class-specific things) as properties within the class itself. I've read some similar SO posts but nothing is close enough to be sure that it isn’t possible (which I think is likely).
Below is the essence of the structure - there's some pseudo code towards the end:
MustInherit Class BaseClass
Shared Property Endpoint As String
End Class
Class Person
Inherits BaseClass
Property Age As Integer
Property Name As String
Sub New()
_Endpoint = "/GetPerson"
End Sub
End Class
Class Event
Inherits BaseClass
Property When As Date
Property Type As String
Sub New()
_Endpoint = "/GetEvent"
End Sub
End Class
Function Retrieve(T As BaseClass)(Id As String) As T
Dim oResp As HttpResponse = MakeGetCall(T.Endpoint, Id) <- T.Endpoint throws a compile error
Return Deserialize(Of T)(oResp.Content)
End Function
Dim oPerson As Person = Retrieve(Of Person)("123")
Dim oEvent As Event = Retrieve(Of Event)("123")
To my tiny mind, I would have thought that, since T’s base class is BaseClass which contains the property Endpoint, I’d be ok. But seemingly not.
I've tried a fair few things from here on SO and other places to overcome this to no avail. Yes, I realize I could perform some kind of endpoint look-up based on the type of T but the above represents a very clean solution and I’d like to get it to work if possible.
Any ideas?
Assuming you want EndPoint to be different for each subclass, you should use MustOverride instead of Shared...
MustInherit Class BaseClass
Public MustOverride Property EndPoint As String
End Class
Then return a constant in each subclass
Class Person
Inherits BaseClass
Public Overrides Property EndPoint As String
Get
Return "/Person"
End Get
You might want to declare EndPoint as ReadOnly too.
The small limitation is that you'll need an instance of the class to access EndPoint (since it isn't Shared). If you have a parameterless constructor, you could use (New Person).EndPoint where needed.

Make static member persistent

I have one class with a private static (shared, since I'm in VB.BET) field and its associated public static property, since it stores one variable that should be the same to all the instances of this class.
My Class looks like this:
Public MustInherit Class NitrogenController
Private _active As Boolean
Private Shared _controlInterval As TimeSpan
Private _lastControlTime As Date
Public Property Active() As Boolean
Public Shared Property ControlInterval() As System.TimeSpan
'other properies that must be persisted
Public Function Control() As Boolean
If Not Now > _lastControlTime.Add(_controlInterval) Or Not _active Then
Return False
Else
DoControl()
_lastControlTime = Now
Return True
End If
End Function
End Class
The problem arrives when trying to binary serialize these kind of objects, since this shared field is nos being properly stored and returns to its default value when deserializing.
I suppose this is the expected behaviour, so my question is... how can I make a shared field persistent? I have read some comments to similar questions that say that this is a bad design, but it really makes sense (AFAIK) in my case, since this variable should be the same to all the object, but can be changed by the user and therefore should be stored.
Can you suggest another way of doing it?
Thanks!
What you have read, in my opinion, is correct. This is, likely, a bad design. However, if you must, there are two ways to do this with the XmlSerializer. The easy way would be to simply add a public instance (non-shared) property which has a getter and setter which simply wrap the shared property, for instance:
Public MustInherit Class NitrogenController
Public Shared Property ControlInterval As TimeSpan
Public Property CurrentControlInterval() As TimeSpan
Get
Return ControlInterval
End Get
Set(value As TimeSpan)
ControlInterval = value
End Set
End Property
End Class
If you aren't satisfied with that method, the second, more involved, option would be to override the default serialization logic by implementing the ISerializable interface.

Issue with generics, interfaces, and casting

I recently added an interface to some custom user controls I have implemented. The interface is pretty basic. It has one method that supports chaining:
Public Interface IMyInterface(Of T As WebControl)
Function DoSomething() As T
End Interface
The implementations are also pretty basic:
Public Class MyCustomControl
Inherits CompositeControl
Implements IMyInterface(Of MyCustomControl)
Public Function DoSomething() As MyCustomControl _
Implements IMyInterface(Of MyCustomControl).DoSomething
' do stuff
Return Me
End Class
Everything works fine up to this point. The issues arise when I attempt to loop over a collection of controls that all implement the IMyInterface interface, like so:
Dim myList = New List(Of IMyInterface(Of WebControl))
myList.Add(someCustomControl)
myList.ForEach(Sub(i) i.DoSomething())
someCustomControl is a MyCustomControl which implements IMyInterface(Of MyCustomControl) instead of IMyInterface(Of WebControl).
I am getting this error on the second line (where I try to add someCustomControl):
Option Strict On disallows implicit conversions from 'MyCustomControl' to 'IMyInterface(Of WebControl)'.
Is there any way to get around this error? I am close to having it working but I do not know enough about generics to get beyond this point.
Covariance is a language feature that was introduced in VS 2010, and solves your problem. You need to define your generic such that the type T has the Out keyword in front of it:
Public Interface IMyInterface(Of Out T As WebControl)
Function DoSomething() As T
End Interface
When you use the Out keyword, you are using covariance. It allows generics of a more derived type to be used in place of a generic with the base type. So in your case it will allow a IMyInterface(Of MyCustomControl)) object in places where the code would normally expect IMyInterface(Of WebControl)), such as your for loop.
Note that covariance has a restriction. The covariant type T can only be used as a function return value, and not as a parameter into a function (or sub). For example, if the DoSomething signature in IMyInterface looked like this the compiler would complain:
' Here the type T is used as an input param - compiler error
Sub DoSomething(ByVal sampleArg As T)
Given your chaining scenario, I don't think the above restriction is a problem.
More Info at MSDN:
Covariance and Contravariance
Creating Variant Generic Interfaces
I don't know what your function DoSomething does, but I try assigning the instance's CssClass in there for testing purpose.
Declare the interface as follows:
Public Interface IMyInterface(Of Out T As WebControl)
Function DoSomething() As T
End Interface
Notice the Out T parameter.
Create 2 controls that implement the interface:
Public Class MyCustomControl1
Inherits CompositeControl
Implements IMyInterface(Of MyCustomControl1)
Public Function DoSomething() As MyCustomControl1 Implements IMyInterface(Of MyCustomControl1).DoSomething
' do stuff
Me.CssClass = "XXX"
Return Me
End Function
End Class
Public Class MyCustomControl2
Inherits CompositeControl
Implements IMyInterface(Of MyCustomControl2)
Public Function DoSomething() As MyCustomControl2 Implements IMyInterface(Of MyCustomControl2).DoSomething
' do stuff
Me.CssClass = "YYY"
Return Me
End Function
End Class
On a test page's PageLoad event:
Dim someCustomControl As New MyCustomControl1
Dim someCustomControl2 As New MyCustomControl2
Dim myList = New List(Of IMyInterface(Of WebControl))
myList.Add(someCustomControl)
myList.Add(someCustomControl2)
myList.ForEach(Sub(i) Literal1.Text &= i.DoSomething.CssClass & "<br />")
The result is, the CssClass property of both someCustomControl & someCustomControl2 are set to the respective values.
This shows that the interface function DoSomething was successfully called and the instance changed.
You will need to cast the object before adding it:
myList.Add(CType(someCustomControl, IMyInterface(Of WebControl)))
You may also want to concider making the interface not generic and your "DoWork" method return type as the interface itself.
Public Interface IMyInterface
Function DoSomething() As IMyInterface
End Interface
When you have to specify the type in the interface definition it kind of takes away from the power of interfaces (not having to know about the implementation).

Breaking BLL (Business Logic Layer) to BLL and DAL (Data Access Layer)

Please see the code below:
Imports Microsoft.VisualBasic
Public Class PersonBLL
Private Name As String
Private Age As Integer
Dim objPersonDAL As New PersonDAL
Dim objPerson As Person
Public Sub getPersonByID()
objPerson = objPersonDAL.getPersonByID()
MsgBox(objPerson.Name)
End Sub
End Class
Public Class PersonDAL
Private Name As String
Private Age As Integer
Public Function getPersonByID() As Person
'Connect to database and get Person. Return a person object
Dim p1 As New Person
p1.Name = "Ian"
p1.Age = 30
Return p1
End Function
End Class
Public Class Person
Private _Name As String
Private _Age As Integer
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Public Property Age() As Integer
Get
Return _Age
End Get
Set(ByVal value As Integer)
_Age = value
End Set
End Property
End Class
PersonBLL calls PersonDAL and returns a Person object. Is this the correct approach? i.e. I have identified a persistent class and created a corresponding DAL class with a function for accessing the data and returning the Person object.
There is a comment that states that this question is "subjective". I agree with this. I realise that the design depends on the requirements of the project. Are there any principles documented for designing a DAL similar to SOLID (single responsibility etc) etc.
Yes, your question demonstrates a very clean way to separate the logic into layers. The PersonBLL class would be part of the business layer, the PersonDAL class would be part of the data access layer, and the Person class would be part of the data transfer objects (DTO) layer. This is a very common way to separate your layers which works well in many situations.
My only recommendations would be:
You should put each layer in their own namespaces, if not also their own class library projects.
You should not show a message box from the business layer. I assume you only did this as a means of demonstration, but just in case, I thought I should mention it. Showing a message box should be part of the UI layer. For instance, if you were calling PersonBLL.getPersonByID from a windows service or a web service, showing a message box would be entirely inappropriate.
Typically, all methods are PascalCase, not camelCase. Some people prefer to make private methods camel case, but certainly public methods shouldn't be camel case.
Consider using dependency-injection techniques (DI) to inject the data access object into the business object.
Dependency Injection
Here's an example of how to do this with DI techniques:
Public Class BusinessFactory
Public Function NewPersonBusiness() As IPersonBusiness
Return New PersonBusiness(New PersonDataAccess())
End Function
End Class
Public Class PersonBusiness
Implements IPersonBusiness
Public Sub New(personDataAccess As IPersonDataAccess)
_personDataAccess = personDataAccess
End Sub
Private _personDataAccess As IPersonDataAccess
Public Function GetPersonByID() As PersonDto Implements IPersonBusiness.GetPersonByID
Return _personDataAccess.GetPersonByID()
End Sub
End Class
Public Interface IPersonBusiness
Function GetPersonByID() As PersonDto
End Interface
Public Interface IPersonDataAccess
Function GetPersonById() As PersonDto
End Interface
Public Class PersonDto
Private _name As String
Private _age As Integer
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Age() As Integer
Get
Return _age
End Get
Set(ByVal value As Integer)
_age = value
End Set
End Property
End Class
Doing it this way has many advantages. You can have multiple interchangeable data access layer implementations, so it's more flexible. Also, you can inject a fake data access object when you want to unit test the business class. DI design avoids many of the traps that lead to buggy, spaghetti code.
With DI, it is typically recommended that you ask for dependency objects as an interface rather than as a concrete type (e.g. IPersonDataAccess rather than PersonDataAccess). Doing so can be a little bit of a hassle, but you get use to it quickly. Since you are often, at that point, creating one interface for every class, it's convenient to just put the interface in the same code file as the class. So, for instance, PersonBusiness.vb would contain both the PersonDataAccess class and the IPersonDataAccess interface.
There are two reasons why using interfaces, rather than classes, for your dependencies is important:
It ensures that the design is flexible. You want to be able to override every public member of the dependency type so that you can create any kind of concrete implementation. There are other ways to do this. For instance, you could skip creating the IPersonDataAcess interface by simply marking every public property and method in the PersonDataAccess class with the Overrideable modifier, but there's nothing forcing you to do that. Even if you always remembered to do so, that doesn't mean someone else working on your code would know they should do that.
DI is often tied-in with unit testing because it is the best tool available for ensuring that code is testable. When unit testing, it is particularly important that you are able to override ever member in a dependency type so you can make a "fake" object that works just the way you need it to work in order to properly perform the unit test. These "fake" objects are called mocks.
You are being more technically honest about what your dependency is. In reality, you aren't really saying that your dependency is actually an instance of the PersonDataAccess class. In actuality, your dependency is any object that happens to have that same public interface. By asking for the class, you are implying that you need a particular implementation, which is a lie. If you have designed it properly, you only care about the interface being the same, so by asking only for the interface itself, you are specifying precisely what you mean to specify :)

What does VB.Net For Each Loop look at to Infer the Type

In the following code,
For Each item in MyCollection
...
Next
What does the compiler use to determine the type of item?
For example let say I have this class, which is inheriting a non generic collection,
Public Class BaseDataObjectGenericCollection(Of T)
Inherits BaseDataObjectCollection
End Class
A for each loop still infers the Item type as Object. How would I have to modify the above class to make the type inference work?
Edit: Per Beatles1692's answer, Implementing IEnumerator(Of T) kinda works. The base class already has a GetEnumerator function, inherited from CollectionBase, so I my implementation looked like this,
Public Function GetEnumerator1() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
Return MyBase.Cast(Of T)().GetEnumerator
End Function
However, the for loop still infers the type as object. But, if I change the interface implementation to this,
Public Shadows Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
Return MyBase.Cast(Of T)().GetEnumerator
End Function
That works, the for loop gets the type inference correct. So I guess the question is now, does For Each just look for a function called GetEnumerator ?
Well, there's only one place to go for a question like this. The spec!
Section 10.9.3 discusses For Each statements. According to it:
[if] local variable type inference is being used, then the identifier defines a new local variable whose scope is the entire For loop and whose type is the element type of the collection (Object if the enumerator expression is typed as Object).
"collection" here seems vague, but it's precisely defined on the next page. Essentially, the type must have a GetEnumerator() call, and this enumerator must (a) have a MoveNext() method that returns a boolean type, and (b) have a Current property. The type of the Current property is the type that will be inferred by the compiler. Note it actually has nothing to do with IEnumerator or IEnumerable...you just have to fit the prescribed pattern. Consider this code:
Option Infer On
Public Module M
Sub Main()
For Each x In New SomeClass()
Next
End Sub
End Module
Public Class SomeClass
Public Function GetEnumerator() As MyEnumerator
Return New MyEnumerator()
End Function
End Class
Public Class MyEnumerator
Public ReadOnly Property Current As Integer
Get
Return 42
End Get
End Property
Public Function MoveNext() As Boolean
Return True
End Function
End Class
The type of "x" in the Sub Main() is Integer, since the Current property returns Integer.
Either you should write :
For Each Item As SpecificType In MyCollection
....
Next
Then it will cast Item to SpecificType in each loop or your collection should have implemented IEnumerable(Of T)