IEnumerable interface as a type? - vb.net

While learning to use LINQ in VB.NET, I came across the following:
Dim x As IEnumerable = (some LINQ query)
If you can't instantiate an interface, but only a concrete implementation of it, why is this allowed? Is there some difference between doing
Dim x as (Type) and
Dim x as New (Type)?

Yes, a big difference. In the code you give, you're declaring a variable that will point at some instantiated thing. It doesn't necessarily know what type of thing it is, but it knows it implements IEnumerable. In the code you gave, the actual instantiation as some concrete type (that implements IEnumerable) is handled by LINQ. The part that goes on the right has to result in a concrete instatiation.

Related

Parameter.GetType() - Does the type has to be known at compilation time?

is something like this possible - and if so how?
Public Sub CreateGenericList(ByVal SampleObject As Object)
Dim genericList as new List(Of SampleObject.GetType())
End Function
I want to create a class that is able to deserialize a given XML-file.
The XML-file contains serialized values of a custom type, which is unknown at compilation time.
I thought it might be possible to just initialize the class with a parameter SampleObject and to then get that SampleObject's type for all further progressing.
But it seems as if the type for all operations has to be known at compilation time?
Is there a way around it or can you explain the problem to me?
The code example above is just to illustrate my problem
Thanks for the help,
Janis
Edit: Your answers might allready have solved the problem, I will read more on the topics "reflection" and "generics" and keep you up to date if i make any progress. So thanks allot for the help.
For those still interested:
I was asked for the purpose of my question and will try to explain it as best i can.
Public Function ReadAllObjects() As List(Of myObjectType)
Dim result As New List(Of myObjectType)
Dim ObjectSerializer As New System.Xml.Serialization.XmlSerializer(result.GetType)
Dim FileReader As New System.IO.FileStream(My.Settings.XMLPath, System.IO.FileMode.Open)
result = TryCast(ObjectSerializer.Deserialize(FileReader), List(Of myObjectType))
FileReader.Close()
RaiseEvent ReadingFinished()
Return result
End Function
This pretty much sums up what I want to create: A EasyXmlHandling.dll for further use, which will be initialized with the currently used variable type.
It is then supposed to be able to write and read from/to an XML-File in a really easy way, by just calling "ReadAllObjects" (returns a List of myObjectType) or "AddObject(ByVal theNewObject)"... (more functions)
I got all that to work with a custom class as type, so i could now easily re-use the EasyXmlHandling-code by just replacing that type in the sourcecode with whatever new class i will want to use.
I though would prefer to just call the .dll with a sample object (or the type of it) and to have it do everything else automaticly.
I hope that was understandable, but neither my english nor my technical vocabulary are really good ;)
So thanks again for the help and for reading through this.
I will try to get it to work with all your previous answers and will update the topic when i make further progress.
No, that is not possible (at least, not without using reflection). The whole point of specifying the type in a generic list, or any other generic type, is so that the compiler can perform compile-time type checking. If you aren't specifying the type at compile-time, there is no benefit to it at all. Beyond there being no benefit, it's also simply not supported. If you don't know the type at compile time, you should just use Object instead, since that will work with objects of any type, for instance:
Dim myList As New List(Of Object)()
If you need a list, however, which only allows one type of item, but that type is unknown at compile time, that is possible to do, but you would probably need to create your own non-generic list class for something like that. As far as I know, there is no non-generic list class provided in the framework which restricts its items to a single specified type.
Update
Now that you've explained your reason for doing this, it's clear that generics are your solution. For instance, you could implement it as as generic function, like this:
Public Function ReadAllObjects(Of T)() As List(Of T)
Dim result As New List(Of T)
Dim ObjectSerializer As New System.Xml.Serialization.XmlSerializer(result.GetType)
Dim FileReader As New System.IO.FileStream(My.Settings.XMLPath, System.IO.FileMode.Open)
result = TryCast(ObjectSerializer.Deserialize(FileReader), List(Of T))
FileReader.Close()
RaiseEvent ReadingFinished()
Return result
End Function
Then, you could call it, like this, passing it which ever type you want:
Dim cars As New List(Of Car) = ReadAllObjects(Of Car)()
Dim boats As New List(Of Boat) = ReadAllObjects(Of Boat)()
As you can see, that is the whole purpose of generics. They are a very powerful tool when you any to keep your code type-specific, but still be able to re-use it with different types. Reflection, on the other-hand is not a good fit in this particular situation. Reflection is also very useful, but should always be considered an option of last resort. If there is another way to do it, without reflection, that's usually the better way.

How do I determine if a value is an instance of a generic type, ignoring the type parameter, in vb.net?

I have a class C(Of T). I want to determine if some given value has type C, regardless of what T is. For example, I might want to determine if a value is a strongly-typed list, regardless what type of items the list stores.
I just need to know how to do it in VB.net. In Java the syntax is like this:
var result = obj instanceof Gen2<?>;
I believe a compact solution for your problem would be:
Dim result = (obj.GetType().GetGenericTypeDefinition().Equals(GetType(Gen2(Of ))))
Explanation:
Gets the Type object representing the base type of instance obj
Gets the generic type underlying the compiler instance type.
Gets the generic type of Gen2 without a qualifying parameter.
Compares the two generics to see if they are equal and returns the result.
It's not nearly as compact as the Java solution you posted (unless I'm mistaken, C# doesn't support either the instanceof keyword or the Java generic wildcard syntax), but it will work.
Edit: Prompted by Cory Larson's comment below, I should add that while the method I posted only works for directly comparing the generic to a known generic type, if you want to find out if it implements a generic interface, use:
Dim result = (obj.GetType().GetGenericTypeDefinition().GetInterface(GetType(IMyGeneric(Of )).FullName) IsNot Nothing)
Sure, sort of. For example:
Dim obj As IList(Of Double) = New List(Of Double)
Dim result As Boolean = obj.GetType().IsGenericType AndAlso _
obj.GetType().GetGenericTypeDefinition().Equals(GetType(IList(Of )))
For that, the result is False. If you change the comparison from IList(Of ) to just List(Of ), then it works.
Dim obj As IList(Of Double) = New List(Of Double)
Dim result As Boolean = obj.GetType().IsGenericType AndAlso _
obj.GetType().GetGenericTypeDefinition().Equals(GetType(List(Of )))
Will return True.
EDIT: Dang, Dan Story got it first.
If you are seeking to find out whether a type is a Foo(Of T) because you're interested in using some property which does not depend upon T, I would suggest that you should make that property available in either a non-generic base class or a non-generic interface. For example, if defining an ISuperCollection(Of T) which provides array-like access, one could offer a non-generic ISuperCollection collection which implements methods Count, RemoveAt, CompareAt, SwapAt, and RotateAt (calling RotateAt(4,3,1) would rotate three items, starting at item 4, up one spot, thus replacing item 5 with 4, 6 with 5, and 4 with the old value of 6), and have ISuperCollection(Of T) inherit from that.
BTW, if you segregate reader interfaces from writer interfaces, the reader interfaces can be covariant and the writer interfaces contravariant. If any property or indexer implements both read- and write- functions, you'll need to define a read-write interface which includes read-write implementations of any such property or indexer; a slight nuisance, but IMHO worth the small additional effort.

Different ways to declare/define variables?

This is a VB.Net newbie question. I'm confused at the different ways to declare and define variables.
Here's an example:
Dim URL As String = http://www.c-sharpcorner.com/default.asp
Dim request As HttpWebRequest = WebRequest.Create(URL)
Dim response As HttpWebResponse = request.GetResponse()
Dim reader As StreamReader = New StreamReader(response.GetResponseStream())
When should I use 1. nothing, 2. call the Create() method, 3. Call another method of the object besides Create(), and 4. use the New word?
Most primitive types (Int32, String etc) in .Net have a literal syntax that allows to you declare a new instance. Where this is available, it should probably be your first choice. Your URL variable from above would be an example of this.
Your next choice would probably be the New keyword. This is good where the type that you are trying to instantiate is known at design time. This might not be appropriate for example if you are just trying to instantiate an instance of a type that implements an interface but do not care about the concrete type of the object that is returned.
A design pattern that you can use in this case (the type is not known at design time) is the Factory Method. The way that the Factory Method is initialized, can influence the type of the object that it returns.
If a class does not have an externally visible constructor then it is probably because the developer of that class wanted to reserve the right to decide at runtime which type he will return. In this case, he will generally provide a Factory Method (prefixed with the Create keyword by convention). The method will not necessarily be on the class that you are trying to instantiate but might be added to some other class in the API that has the context required to firstly make the decision as to which concrete class to return and secondly has the ability to provide the necessary dependencies to create the object.
In summary your decision path should probably be..
Literal
Constructor
Factory Method
As an interesting aside - the DateTime data type is a case where VB.Net has a literal syntax and C# does not. The 31st of May 1999 can be instantiated as a DateTime object in VB.Net using the syntax #5/31/1993#. To instantiate the same date value in C# would require the use of the constructor new DateTime(1999, 5, 31).

Can I qualify the type of a parameter in VB.NET?

This is kind of two questions (one more specific than the other).
If I have a method like this:
Public Function Blah(String Foo)
End Function
Can I qualify Foo against another type (for instance can I require that Foo be a String that also implements IInterface?).
I'm imagining something vaguely similar to this:
Public Function Blah(RandomObject Foo Where RandomObject Is IInterface)
End Function
Additionally, is there any way to qualify the Type parameter?
For instance, can I require that the Type I take as a parameter is of a particular class tree?
Public Function Blah(Type t Where Type Of String)
End Function
I should mention that I am using this in the context of a property of an attribute so the class declaration itself cannot be generic (this is purely focused on qualifying a method parameter rather than typing a class and its methods).
This looks like a case for generics to me. Your method signature would be something like this in VB.NET:
Public Function Blah(Of T As {IImplementedByT})(Foo As T)
This specifies that Foo can be of any type T as long as T implements IImplementedByT. Note that this method can be generic without the containing class needing to be generic. If you want T to be a class derived from RandomClass that also implements this interface, you can specify both constraints:
Public Function Blah(Of T As {RandomClass, IImplementedByT})(Foo As T)
You can do the first for a generic type, but not for a nongeneric type. Basically a variable (including a parameter) can only have one compile-time type, so you can't say "it has to be a Foo and an IBar - you have to pick one or the other. Generics let you say "it has to be some type T where T derives from Foo and implements IBar" though.
Generics is a huge topic - too big to cover in a Stack Overflow answer - but Microsoft has a good introductory article.
As for your second question - no, you can't do that. The Type value will only be known at execution time, so it has to be an execution time check. You can write that check fairly easily though, with Type.IsAssignableFrom.
Not sure what you mean by "Foo be a String that also implements IInterface".
string class is sealed, so you can't inherit from it & hence you cant implement an interface on top of it.
I hope I am on the right page.

Converting Value Type of a Dictionary in VB.net

Public Class A
Public Class B : Inherits A
Dim DictA As Dictionary(Of Integer, A)
Dim DictB As New Dictionary(Of Integer, B)
DictA = DictB
This doesn't work, as the type can't be converted. Is this somehow possible?
No. You're running into the problem of generic variance, which isn't supported in .NET except in a few very particular ways.
Here's the reason: after your last line, you've got a single dictionary with two "views" onto it, effectively. Now imagine you wrote:
DictA.Add(1, New A())
(Apologies if my VB is slightly off.) That's inserted a "non-B" into the dictionary, but DictB thinks that all the values will be instances of B.
One of the main purposes of generics is to catch potential type failures at compile time rather than execution time - which means this code should fail to compile, which indeed it does precisely because of the lack of variance.
It's a bit counter-intuitive when you're used to normal inheritance, but it does make sense. A bunch of bananas isn't just a collection of fruit - it's a collection of bananas.
Java takes a somewhat different stance on this using wildcarding from the caller's side - it would let you see just the "adding" side of the dictionary for DictB, for instance, as anything you add to DictB would be fine in DictA. Java's generics are very different to .NET generics though...
This is a interesting, and quite complex aspect of Static type systems.
The terms you are looking for is Covariance and Contravariance.
The c# language will get this for certain sorts of operations on Generic types in 4.0 though in a somewhat limited form.
You have it to a certain degree already in the form of
object[] x = new string[1];
Which is allowed because arrays are treated covariantly, which means that you could then do the following:
x[0] = new object();
which would throw an Exception at runtime. Do you see how the same would apply to you Dictionaries...
The c# 4.0 spec is still non final so is subject to change but for some discussions and explanations see this question
Unfortunately not. This is a known absence of covariance/contravariance support. The CLR supports it, but the compilers for C# and VB.Net do not.
The next version of C# (4.0) actually does support it now, but not sure about vb.net.
Also, with System.Linq, one of the extension methods is Cast() which would allow you to cast from a collection of one type to another. However it will still return IEnumerable so you need to manipulate a little bit, but I think key-value types will be harder than collections with only one generic type.