VB.net anonymous class with inheritance - vb.net

Imagine I have class like this :
Class A
Public Function Some(str As String) As String
Return "Some " + str
End Function
End Class
I have consuming code like this :
Public Sub Foo()
Dim thisWorks = New With {.prop = "thing"}
Dim thisDoesntWork = New inherits A with { .prop = Some("thing") }
End Sub
I'm trying to create an anonymous type with inheritance so that I can use the methods within. Is this possible ?
Use case : I'm trying to create a class that has methods like Select, From etc. that would help in cleaner query construction. In the consuming code, I would just create an anonymous type inheriting from the class and use the methods.

What you want is not possible (at least not the way you describe it).
From what I think I understood ; you should try to mimic what has been donne for Linq ; an interface (like IEnumerable) with all the method you want (or maybe an abstract class bu that prevent you to inherit from something else) + something else (probably a module if you want them as extension method) defining the Select etc. acting on the interface.
From that point you can create classes which implement the interface and use your custom Select etc. on them

Related

Named Constructor Idiom in VB.NET?

Is using the Named Constructor Idiom possible in VB.NET? I've found many examples in C#/C++ but can't quite wrap my head around how to use it in vb.net. Seems like a better method of keeping my code readable when involving a lot of constructors with similar argument types.
I've never heard this term before, but after a quick search it sounds vaguely like the Static Factory Pattern. The idea is you make the constructor private and use a shared (static in c#) public function to create the new object.
Public Class Foo
Private Sub New()
End Sub
Public Shared Function CreateNew(param as Object) as Foo
Dim obj as New Foo()
obj.Prop = param
return obj
End Function
End Class
You sure can make Named Constructors in VB. The pattern uses a static (Shared in VB) factory method on the class itself, so that the method can be named. (Other Factory patterns involve using a separate Factory class to provide the static method.)
System.Drawing.Color is a simple example. The pattern is implemented underneath as a static (Shared) property. Since no arguments are necessary, the Get method of a Property works just fine:
Public Shared ReadOnly Property Chartreuse As Color
Usage:
Dim favoriteColor as Color = Color.Chartreuse
Or you can make static factory methods to do the same thing.
Public Class TheClass
Public Sub New()
End Sub
Public Sub New(input As String)
'do something with input
End Sub
Public Shared Function MyNamedConstructor() As TheClass
Return New TheClass
End Function
Public Shared Function AnotherNamedConstructor() As TheClass
Return New TheClass("Another Name")
End Function
End Class
As for whether this pattern is "better" than overloading constructors, that's really an opinion. Personally, I would just overload the constructors. As you can see in the example above, the constructors need to be there anyway.
I suggest using the Named Constructor pattern when you have only a few possible ways to construct your class/struct, but consumers of your class/struct will be using those few constructors often, and with different input values to those constructors (as in the System.Drawing.Color example).
The Name in 'Named Constructor' doesn't represent a name for the constructor itself, but for the object resulting from the constructor. If your named constructor can be used to create two objects that don't feel right to give the same name to, then don't give the constructor that name.

What is the purpose of declaring a Class within another Class?

I come from the VBA world where options to breakdown your code into classes, namespaces, and modules is limited. Now I just landed in a world where the options are many, and I feel lost.
I would like to know what is the purpose of declaring a Class within another Class? (see example below)
Class FirstClass
Public OnePropertyInside As String
Class SecondClass
Public AnotherProperty As String
End Class
End Class
If I create a new instance of FirstClass (say myFirstClass), SecondClass is not instantiated.
Even more bizzare (to me at least), is that intelissense offers me myFirstClass.SecondClass. Obviously, because the class is not instantiated, I cannot access any of its members.
So, is that usefull only if the SecondClass contains shared members?
To try answering that question I added a shared member within SecondClass:
Class FirstClass
Public OnePropertyInside As String
Class SecondClass
Public AnotherProperty As String
Public Shared SharedProperty As String
End Class
End Class
I ran a few tests which brought secondary questions (see comments in code)
Sub Main()
Dim myFirstClass As New FirstClass
'Works as expected
Console.WriteLine(myFirstClass.OneProperty)
'What is the difference between the two lines below?
Console.WriteLine(myFirstClass.SecondClass.SharedProperty)
Console.WriteLine(FirstClass.SecondClass.SharedProperty)
'This line cannot be compiled, this demonstrates SecondClass is not instantiated when FirstClass is.
Console.WriteLine(myFirstClass.SecondClass.AnotherProperty)
Dim mySecondClass As New FirstClass.SecondClass
'Works as expected, but I feel this hierarchy should better be dealt with through a namespace statement?
Console.WriteLine(mySecondClass.AnotherProperty)
End Sub
You can think of it as if the inner most class is a helper class of sorts. It may not even need to be used at all. Nesting the inner class(or simply nested class) inside the outer class gives you access to all of the members of the outer one. You can even access the private members inside that initial outer class.
Edit: For clarification, I mean to say that the the inner can access the private members of the outer, not the other way around.
You usually do this because you want to restrict the scope of the nested class.
So, if you only need to use this class from within the "parent" class (in terms of scope), then its usually a good idea to define it as a nested class.
If you might might need to use the class outside of its assembly, then it is better to define it as a completely separate class (in its own file), and then define your relationship accordingly. You will need to instantiate one within the other (this is the same whether its seperate or nested - so its location is largely irrelevant for that point).
When you do that, and the inner class is accessible to other classes (it's accessibility is Public or Friend), the outer class basically just works like a namespace. So for instance, using your example, you could create a new object of the nested class without ever creating one of the outer class:
Dim x As New FirstClass.SecondClass()
The most obvious benefit is the structural organization of the code, much like namespaces and code files. So, for instance, it's not uncommon to use nested classes for constants, to help better organize them:
Public Class Urls
Public Class Processing
Public Const Submit As String = "..."
Public Const Cancel As String = "..."
End Class
Public Class Reporting
Public Const Daily As String = "..."
Public Const Weekly As String = "..."
End Class
End Class
' ...
Dim url As String = Urls.Reporting.Daily
However, outside of the narrow set of situations where things like that are useful, most people would prefer to not nest public classes at all.
However, as others have mentioned, the one place where you really will see nested classes used fairly regularly is for Private ones. If you need some small helper class which will have no use to code outside of your class, there's no reason to expose it. Even if you set it's accessibility to Friend, it will still be visible to all the other classes in the same project. Therefore, if you really want to hide it from everything else, you'll want to make it a nested private class. For instance:
Public Class MyClass
Public Function GetTheIdOfSomething() As Integer
Dim d As Details = GetDetailsAboutSomething()
If d.Value Is Nothing Then
Return d.Id
Else
Throw New Exception()
End If
End Sub
Private Function GetDetailsAboutSomething() As Details
' ... return a Details object
End Function
Private Class Details
Public Property Id As Integer
Public Property Value As String
End Class
End Class

Passing type argument to a generic custom class

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)

vbscript static class variables/methods?

Is there a way to have one variable per class in vbscript?
If not what is the best way to emulate it? Prefixing a global variable declared next to the class?
Also is there a way to declare static/class methods(for a static constructor) or am I force to prefix a function?
In languages that support class-level/static data or methods you can
associate/bind data or methods explicitly to the set of objects defined by the class. So you can have Customer.Count and Product.Count and a plain Count (or ##Count) in Customer code will access the right number.
use such data or method without having an instance of the class (yet).
VBScript does not support static data or methods. You have to use global data or functions/subs and do the associating in your mind (perhaps with a little help from a naming convention). Accessing these 'static'=global elements without an object is trivial, but - obviously - should be done with care.
You can embed one or more singleton objects or code references (GetRef()) in your objects to bind them closer to the class, but that will increase the size of the instances.
You can do something like this to sort of emulate a static class:
Class Defines_
Public Sub DoSomethingUseful
End Sub
End Class
Dim Defines : Set Defines = New Defines_
...
Defines.DoSomethingUseful
This can be used to give you something analogous to constructors (really, factory methods):
Class Something
Private mValue
Public Property Get Value : Value = mValue : End Property
Public Property Let Value(x) : mValue = x : End Property
End Class
Class SomethingFactory_
Public Function Create(value)
Set Create = New Something
Create.Value = value
End Function
End Class
Dim SomethingFactory : Set SomethingFactory = New SomethingFactory_
...
Dim something : Set something = SomethingFactory.Create(5)

Factory method for generics in VB.NET

I want to create a factory for generic classes in VB.NET and I am running into issues.
What I have are two interfaces:
IPersistentObject and IPManagerBase(Of T as IPersistentObject)
The logic is that for each type of peristent object I have a corresponding manager class handling query logic.
Now I have a base class like this:
public class PManagerBase(Of T as IPersistentObject) Implements IPManagerBase(of T)
So, now in the real world I have a persistent type "PUser" and a corresponding manager declared like this:
public class PUserManager implements PManagerBase(Of PUser)
I have about 100 of those persistent objects and corresponding manager classes.
Now I want to have a factory, which I would invoke like this (removing the details):
MyFactory.CreateManager<PUserManager>()
I am creating my Factory like this
public class MyFactory
public shared function CreateManager(Of T as {PManagerBase(Of IPersistentObject), New}) as T
return new T()
end function
end class
Looks great.
Now I want to invoke it:
Dim myManager = MyFactory.CreateManager<PUserManager>()
What happens?
I get a compile error: "PUserManager does not implement/inherit PManagerBase(Of IPersistentObject)". I get the message in German so this is a free tranlation.
What would I need to change to make this running?
It works if I declare my factory like this:
public class MyFactory
public shared function CreateManager(Of T as {PManagerBase(Of PUser), New}) as T
return new T()
end function
end class
But then the benefit is gone, since it works only for Managers of the PUser object.
A better solution is
public class MyFactory
public shared function CreateManager(Of T as {PManagerBase(Of U), New}, U as IPersistentObject) as T
return new T()
end function
end class
This works, but I have to call my factory method like this now:
Dim myManager = MyFactory.CreateManager<PUserManager, PUser>()
I don't like this since this is redundant and I don't need U at all in the function. In it's declaration PUserManager is tied to PUser.
Is there a better way? Why is PUserManager not inheriting from PManagerBase(Of IPersistentObject)?
This is a problem with generics, if you are using VS 2010 you may want to take a look at covariance and contravariance and modify your IPManagerBase definition accordingly.