How to bind to Class using Generics in XAML - vb.net

I have created a simple class like this one...
Public Class Localizer(Of T)
Public Shared ReadOnly Property DisplayName(ByVal propertyName As String) As String
Get
...
End Get
End Property
End Class
And I'm attempting to bind to it in XAML something like this...
Header="{x:Static loc:Localizer(Of AircraftReference).DisplayName [IsMilitary]}"
But this must not be the right syntax. This may not even be possible.

There are two problems here.
XAML support for generics is not complete; I don't think you can specify the type parameter in XAML.
However, there's an easy workaround for this problem:
Public Class Localizer(Of T)
Public Shared ReadOnly Property DisplayName As String
Get
...
End Get
End Property
End Class
Public Class AircraftReferenceLocalizer
Inherits Localizer(Of AircraftReference)
End Class
Now you can use:
Header="{x:Static loc:AircraftReferenceLocalizer.DisplayName}"
x:Static does not support parameterized properties, so you cannot pass the string "IsMilitary". I'm afraid you'll have to find a solution without x:Static. It might make sense to describe want problem you want to solve and ask for a solution in a new question.

Related

How can I create a generic class that only works for classes that support certain interface?

Class cacheable(Of T As haveTimeStampandMainStringKey)
Public ReadOnly Property Cache As T
Public ReadOnly Property timestamp As Date
Public Shared Function create(cache1 As T) As cacheable(Of T)
Dim a = New cacheable(Of T)
a._Cache = cache1
a._timestamp = Now
Dim key = T.mainkey 'this things fail to compile
Return a
End Function
End Class
Interface haveTimeStampandMainStringKey
ReadOnly Property TimeStamp As DateTime
ReadOnly Property mainKey As String
End Interface
Basically I want class cacheable to work only with classes that support haveTimeStampandMainStringKey
Yet
Dim key = T.mainkey produces an error
Clearly T supports haveTimeStampandMainStringKey interface. So I should be able to access T.mainkey. I can't. Why? What's wrong with the code?
Why?
It doesn't work because T is a type, not an instance. You need to have an instance to refer to mainKey. You probably want either a.Cache.mainKey or cache1.mainKey.
(If you really want something Shared rather than something attached to an instance, unfortunately, there isn't a good way to do it as it's not supported by .NET except through various reflection-based approaches, see various lamentations about the absence of "static interfaces" over the years.)

Shorthand Notation on an Overrideable Property in VB.Net Not Working

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

Error using multiple Generic Classes in VB.Net

I tried to find a similar issue already posted but simply got confused with what i found.
I have a situation which involves the following objects:-
Reports contain parameters
Documents contain parameters
Report and Document Parameters are similar
Queries contain parameters
Reports, Documents and Queries all have similar Parameters
So I created the following class structure:-
Public MustInherit Class clsBaseCollection(Of TclsBaseChild As clsBase, TclsBaseParent As clsBase)
Public MustInherit Class clsParams(Of TclsParam As clsParam, TclsRootObject As clsRootObject)
Inherits clsBaseCollection(Of TclsParam, TclsRootObject)
Public MustInherit Class clsRepDocParams(Of TclsRepDocParam As clsRepDocParam, TclsReportDocument As clsReportDocument)
Inherits clsParams(Of TclsRepDocParam, TclsReportDocument)
Public Class clsReportParams
Inherits clsRepDocParams(Of clsReportParam, clsReport)
Public MustInherit Class clsReportDocument
MustOverride ReadOnly Property Parameters() As clsRepDocParams(Of clsRepDocParam,clsReportDocument)
Public Class clsReport
Inherits clsReportDocument
Private _Params As clsReportParams
Public Overrides ReadOnly Property Parameters() As clsReportParams
Get
If _Params Is Nothing Then
BeginUpdate()
_Params = New clsReportParams(Me)
EndUpdate()
End If
Return _Params
End Get
End Property
The last property produces the following error:-
‘Public Overrides ReadOnly Property Parameters As clsReportParams' cannot override 'Public MustOverride ReadOnly Property Parameters As clsRepDocParams(Of clsRepDocParam, clsReportDocument)' because they differ by their return types.
I cant see how this is so because I believe I have my classing levels correct!?
Apologies for the lack of tab formatting... im new to the stack overflow site and hopefully i will improve ;)
Cheers
Jeff
The MustOverride property is declared as
As clsRepDocParams(Of clsRepDocParam,clsReportDocument)
Your Override is simply declared as
As clsReportParams
It does not specify the base collection so they do not match. You should probably declare the override as
As clsRepDocParams(Of clsRepDocParam,clsReportDocument)
to match the base class.
It is worth noting that with every additional level of inheritance that you create, you need to be that much more careful to ensure that you design is done very carefully! If I was reviewing that code I would need to be convinced that the complexity was actually going to pay off over the lifetime of the project.

In VB, How do you force an inherited class to use an attribute on the class?

I'm trying to force an inherited class to use a custom attribute. I'm creating a class library where the user who wants to create an item will do so, but be forced to add an attribute (or visual studio will automatically add the default attribute) to their inherited class. Here is what I'm hoping to achieve:
BaseClass.vb:
<CustomAttribute(10)> _
Public Class BaseClass
End Class
MyClass.vb:
<CustomAttribute(12)> _
Public Class MyClass
Inherits BaseClass
Public Sub New()
Mybase.New()
End Sub
End Class
So the thought is that much like when you mark a function as "MustOverride" and then the inherited class must override the function, I want the attribute to be "MustOverride" causing the inherited class to specify the value.
I've tried this, and it will work, but it would be much cleaner if I could use attributes:
BaseClass.vb:
Public MustInherit Class BaseClass
Public MustOverride ReadOnly Property CustomAttribute() As String
End Class
MyClass.vb:
Public Class MyClass
Inherits BaseClass
Public Sub New()
Mybase.New()
End Sub
Public Overrides ReadOnly Property CustomAttribute() As String
Get
Return "testing"
End Get
End Property
End Class
Thank you for any help you can provide.
Scott
Did you consider implementing an interface instead? I assume that you're using a base class as you want to provide some code in the base, if not then an Interface might be better depending on your other requirements:
Interface IBase
ReadOnly Property CustomAttribute() As String
End Interface
It's still very compact and when you type 'Implements IBase' in a new class Visual Studio will fill in the code for you.
There's no way in .NET to force a class to define an attribute at compile time. The best you'll be able to do is check at run-time whether the attribute was defined, and if not to throw an exception.

MustOverride Properties with mixed access level Get / Set

Visual Basic allows for properties with mixed access levels, for example
Public Property Name() as String
Get
End Get
Friend Set(ByVal value As String)
End Set
End Property
Is there a way to define a MustOverride property with mixed getter/setter access level?
Hmm... you can in C# very easily:
public abstract string Foo { get; protected set; }
Unfortunately Reflector creates invalid VB when I decompile that...
EDIT: Having looked at a few bits of documentation, I suspect you can't do this :( The MustOverride documentation states:
Incomplete Declaration. When you
specify MustOverride, you do not
supply any additional lines of code
for the property or procedure, not
even the End Function, End Property,
or End Sub statement.
That suggests to me that you can't specify the different access levels :(