I have an interface IDigitalState defined as
Public Interface IDigitalState
ReadOnly Property Code As Integer
ReadOnly Property Name As String
End Interface
and a structure that implements this interface
Public Structure DigitalState
Implements IDigitalState
Private ReadOnly mCode As Integer
Private ReadOnly mName As String
Public ReadOnly Property Code As Integer Implements IDigitalState.Code
Get
Return mCode
End Get
End Property
Public ReadOnly Property Name As String Implements IDigitalState.Name
Get
Return mName
End Get
End Property
Public Sub New(ByVal code As Integer, name As String)
mCode = code
mName = name
End Sub
End Structure
What I wanted to do was declare a variable as a nullable type of IDigitalState. I understand why I cant do this because the interface may be implemented by a class which is not allowed to be nullable. Is there a way to define the interface so that it can only be implemented by a structure. I'm doubting it's possible but thought it would be worth looking into.
You can do this in combination with generics. For instance:
Sub Test(Of T As {IDigitalState, Structure})()
Dim something As T? = GetEitherValueOrNull …
End Sub
The key here is that you operate on a concrete (generic) type T which has two conditions:
it is a structure, and
it implements IDigitalState.
Or you can just use a normal variable of interface type, which can be Nothing, without the need for a Nullable.
No, there is no way.
However, you can type.
Dim nullableIDigitalState As IDigitalState = nothing
which would be declaring a variable of type IDigitalState as null. If you are talking about the Nullable<> generic that has a where constraint that limits to value types so it would only accept a structure variant of IDigitalState.
Am I missing your point?
The only situations in which it would be meaningful to restrict interface implementations to structure types are those in which the interface type is going to be used as a generic constraint, and never as a storage location type. In such situations, any code which requires type parameter to be a struct that implements the interface can specify that. Nothing would prevent classes from implementing the interface, but so what? A variable of type IDigitalState could hold a reference to a class that implements that interface, but could not be passed as a generic parameter of type T As {Structure,IDigitalState}, so code which requires a structure-type implementation wouldn't care that such things might exist.
Note, btw, that storing a struct that implements IDigitalState into a variable of type IDigitalState will effectively create a new class object with fields matching those of the structure, and store a reference to that object. If you wish to ensure that a struct which implements an interface, will behave like a struct rather than a class, you need to pass or hold it in a variable with an interface-constrained generic type, rather than in a variable of the interface type.
Related
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.
In my VB.Net code, I know that when I declare a property in a class I can do so using the shorthand of, for example, Public Property Prop1 As String and .Net automatically creates a private variable _Prop1 that I can refer to within my class.
I also know that I can refer to that variable within my code using either _Prop1 or by Prop1.
Now since I've always assumed that the preferred method is to use the private variable, I've always tried to make modifications / write code within my class referring to _Prop1. This is where my problem now comes in...
I have the following situation:
Public Class MyClass_Base
Public Overridable Property Prop1 As String = "val1"
Public Sub Test()
If _Prop1 = ....
End Sub
End Class
Public Class MyClass
Inherits MyClass_Base
Public Overrides Property Prop1 As String = "val2"
End Class
Basically, I define the property as Overridable in my base class, now when I get to the Test() subroutine, _Prop1 has the value of Nothing. However Prop1 has the correct value of val2.
Programming gurus out there, what is the correct way to deal with this situation?
Do I ignore the auto-created prive variable _Prop1 and work with the public Prop1 or is there something else I should add in / not even use the shorthand notation for this and write my own getter / setter logic to ensure things change as I would like?
Thanks!!!
I think you've answered your own question. You should absolutely not rely on hidden compiler mechanics in your own code. You're referencing a variable that you did not declare and there is no guarantee in the framework that this variable will be there (or work as you might expect, as you've discovered) - it's a hack to use it, so don't.
Unless you have a very good reason not to, code in the class should reference the public property just the same as code using the class would. If you're using automatic properties then there is no difference between doing that and using the private variable. It also has the benefit that if you do, at a later time, decide to implement explicit getters and setters that your code does not break and that your new getters and setters get called.
To explore the reason you get the unexpected result, in declaring
Public Overrides Property Prop1 As String = "val2"
You end up with two different _Prop1 variables - MyClass_Base._Prop1 and MyClass._Prop1. When you then call Test(), you are calling the base class method and that will refer to the base class's _Prop1 variable which has not been set to anything since you have overriden the implicit variable, getter, and setter in the subclass.
To illustrate the point, this is similar to :
Public Class MyClass_Base
Private _Prop1 As String = "val1"
Public Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Public Class MySubClass
Inherits MyClass_Base
Private _Prop1 As String = "val2"
End Class
Sub Main()
Dim class1 As New MyClass_Base
Dim class2 As New MySubClass
class1.Test()
class2.Test()
End Sub
Where your output will be :
val1
val1
In the above case MyClass_Base._Prop1 is always initialized, however, while in your case, it is not. In either case, the Test() method belongs to the base class so it will always refer to its own _Prop1 and not any variables of the same name declared in subclasses.
If you do need to refer to the private field, for whatever reason, you have to be very careful about how you do it (and the implications that follow). Any method that does so would need to itself be Overridable if subclasses are intended to work with their own private variables in the same way. Not to suggest that you should continue to use implicit variables, but to demonstrate :
Public Class MyClass_Base
Public Overridable Property Prop1 As String = "val1"
Public Overridable Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Public Class MySubClass
Inherits MyClass_Base
Public Overrides Property Prop1 As String = "val2"
Public Overrides Sub Test()
Console.WriteLine(_Prop1)
End Sub
End Class
Here we get the "expected" result because MySubClass overrides test to reference its own private field. Better to just stick to using the property names.
From the documentation on Auto Implemented Properties:
"Attributes specified for the property do not apply to the backing field."
This is one of those areas where C# and VB.NET need to be aligned.
C# (correctly) does not allow you to access the auto implemented property backing field (without some convoluted work). I honestly don't know what you can access this in VB.
So the rule here is even though you can access the backing field of an auto implemented property you really shouldn't modify this directly (nor should you need to)
If you need to then you should use a defined backing field (with initialisation) and explicit Get and Set
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.
I've seen a lot of chatter on this topic. Though the examples and desired outcomes are always very specific and specialized. Any direction on this is appreciated.
Custom Class:
Public Class customClass(Of T, S)
[include properties]
[include methods]
End Class
Implementation of Class:
dim [string] as string = string.empty
dim [type] as type = [string].gettype
dim instance as customClass(of [type], integer)
Also note, I've read that vb.net does not allow you to pass parameters to its constructor. I refuse to accept that you can't pass a type to a class and generate objects dependent on the type of that argument. Is the only answer to this a function in the class which returns a list of objects cast to the desired type? Your time is appreciated.
This question is motivated by academic research. The above is "what I am trying to do" thanks.
Kind of hard to see what you're trying to do, but if I'm reading this right, you're trying to take a variable and use that as the generic argument. This is not possible in .NET - when you declare a variable of a generic class, you need a compile-time type as the generic argument, so it cannot be the a variable of type Type.
This is important for a couple of reasons, one of which is to ensure that type constraints are met.
So:
Class Foo(Of T)
End Class
Dim x as Type = GetType(String)
Dim y as Foo(Of x)
does not work - you have to do:
Dim y as Foo(Of String)
There's always reflection and expression trees, but that's more of a hack than a solution.
You cannot use dynamic types to call this kind of typed declarations (Of t,s) but you can 'group' or delimit several types using interfaces or inheritance, which could also be very useful.
Class customClass(Of T As iMyInterface, s As iMyInterface)
End Class
Interface iMyInterface
End Interface
Class MyClass1
Implements iMyInterface
End Class
Class MyClass2
Implements iMyInterface
End Class
Dim y As New customClass(Of MyClass1, MyClass2)
In .net, it's possible to use generics so that a function can accept arguments which support one or more interfaces and derive from a base type, even if there does not exist any single type from which all valid argument types derive. For example, one could say:
Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(Param as T)
and be allowed to pass any derivative of SomeBaseType which implements both IInterface1 and IInterface2. This will work even if SomeBaseType does not support Interface1 and Interface2, and classes which do implement those interfaces don't share any common ancestor that also implements them.
This can be very convenient if one won't need to keep the parameter anywhere after the function has exited. Unfortunately, I can't figure out a way to persist the passed-in parameter in such a way that it can later be passed to a similar function, except perhaps by using Reflection. Is there any nice way of doing that?
The closest I've been able to come up with is to define an interface INest (perhaps not the best name--can anyone improve it?) thus:
Interface INest(Of Out T)
Function Nest() As T
End Interface
And for any interface that will be used in combination with others or with base-class "constraint", define a generic version as illustrated below
Interface IFun1
' Any members of the interface go here, e.g. ...'
Sub DoFun1()
End Interface
Interface IFun1(Of Out T)
' This one does nothing but inherit'
Inherits IFun1, INest(Of T)
End Interface
A class which will support multiple interfaces should declare itself as implementing the generic ones, with itself as the type argument.
Class test123a
Inherits sampleBase
Implements IFun1(Of test123a), IFun2(Of test123a), IFun3(Of test123a)
End Class
If that is done, one can define a function argument or class variable that supports multiple constraints thusly:
Dim SomeField as IFun1(Of IFun2(Of IFun3(Of sampleBase)))
and then assign to it any class derived from sampleBase, which implements those interfaces. SomeField will implement IFun1; SomeField.Nest will implement IFun2; SomeField.Nest.Nest will implement IFun3. Note that there's no requirement that IFun1, IFun2, IFun3, or sampleBase share any common derivation other than the generic interfaces inheriting from INest(Of T). Note also that, no matter how many INest-derived interfaces a class implements, it only needs to define one implementation of INest(Of T).Nest.
Not exactly beautiful, but there are two nice things about it: (1) any concrete class which in fact implements the necessary interfaces can be assigned directly to a field declared as above, without a typecast; (2) while fields which chain the types in a different order are not assignment compatible, they may be typecast to each other.
Is there any better way to store something in such a way that it's "known" to support multiple interfaces and derive from a certain base type? Given that one can write such code in a type-safe manner, it would seem like the .net 2.0 CLR could probably support such a thing quite nicely if compilers offered a little assistance. I'm unaware of any particularly nice approach with present compilers, though.
The best way I can think of is to make an abstract storage and generic implementation of this storage. For example (excuse my VB.NET):
MustInherit Class Storage
Public MustOverride Sub DoSomething()
End Class
Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
Inherits Storage
Public Overrides Sub DoSomething()
' do something with Value.
End Sub
Public Value As T
End Class
And usage
Dim S As Storage
Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(ByVal Param As T)
S = New Storage(Of T) With {.Value = Param}
End Sub
Sub UseS()
S.DoSomething();
End Sub
Update: Ok, because we may not be able identify in advance all of the actions:
MustInherit Class Storage
MustOverride ReadOnly Property SomeBaseType As SomeBaseType
MustOverride ReadOnly Property IInterface1 As IInterface1
MustOverride ReadOnly Property IInterface2 As IInterface2
End Class
Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
Inherits Storage
Public Value As T
Public Overrides ReadOnly Property IInterface1 As IInterface1
Get
Return Value
End Get
End Property
Public Overrides ReadOnly Property IInterface2 As IInterface2
Get
Return Value
End Get
End Property
Public Overrides ReadOnly Property SomeBaseType As SomeBaseType
Get
Return Value
End Get
End Property
End Class