Stefan Steiger
Stefan Steiger

Reputation: 82186

Calling a generic function in VB.NET / C#

Question: I want to call a generic function, defined as:

      Public Shared Function DeserializeFromXML(Of T)(Optional ByRef strFileNameAndPath As String = Nothing) As T

Now when I call it, I wanted to do it with any of the variants below:

Dim x As New XMLserialization.cConfiguration
x = XMLserialization.XMLserializeLDAPconfig.DeserializeFromXML(Of x)()
x = XMLserialization.XMLserializeLDAPconfig.DeserializeFromXML(GetType(x))()
x = XMLserialization.XMLserializeLDAPconfig.DeserializeFromXML(Of GetType(x))()

But it doesn't work. I find it very annoying and unreadable having to type

    x = XMLserialization.XMLserializeLDAPconfig.DeserializeFromXML(Of XMLserialization.cConfiguration)()

Is there a way to call a generic function by getting the type from the instance ?

Upvotes: 6

Views: 5330

Answers (6)

Dan Tao
Dan Tao

Reputation: 128327

It sounds to me like you want to create a shorter alias for your XMLserialization.cConfiguration type. Try using the Imports statement to accomplish this:

' at the top of the file
Imports C = XMLserialization.cConfiguration

' somewhere in the body of the file
Dim x = XMLserialization.XMLserializeLDAPconfig.DeserializeFromXML(Of C)()

Upvotes: 4

Keith
Keith

Reputation: 155662

There's a good reason why you can't do this easily in code and why the reflection is so much extra work: generics are all about preserving type, so you can have a List(Of Integer) instead of a List(Of Object) and have to cast/box everything, and they improve code-maintainability by maintaining strong typing through the code (so you get fewer run-time cast and type exceptions).

Generics are really compile-time. They let you defer the type being specified so that your generic code can be re-used or have the type specified by another assembly.

However your deserialisation is run time - you don't know what type you'll have when you're writing the code, which is why you need a variable to hold the type. In this case there isn't really any benefit to having the generic code - your serialisation costs will be orders of magnitude greater than the boxing cost, and there's no code-maintainability benefit for the strongly typed result as you still don't know what it is at compile-time.

In short, this being hard is .Net's way of telling you to review your initial assumptions - change your method to:

Public Shared Function DeserializeFromXML(Optional ByRef strFileNameAndPath As String = Nothing) As Object

And then cast your result from object to your XMLserialization.cConfiguration class.

Upvotes: 1

Mark Hurd
Mark Hurd

Reputation: 10931

[This is answering the question as asked, not necessarily solving your bigger issue.]

To avoid the Of cConfiguration being required you could include an ignored ByVal Configuration As T in the generic method.

Then you could say

x = DeserializeFromXML(x)

But @DanTao's answer is probably better than mine unless you find a use for the Configuration parameter.

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062770

Generics and reflection make very poor friends. However, you can do this via MakeGenericMethod. However, that is going to be hard and ugly.

Since XmlSerializer is based around Type instance - I would reverse things: have the realy code Type based, and call into that from the shallow generic version; example in C#:

public T DeserializeFromXML<T>(string path) {
   return (T)DeserializeFromXML(typeof(T), path);
}
public object DeserializeFromXML(Type type, string path) {
    //TODO: real code
}

Upvotes: 4

John M Gant
John M Gant

Reputation: 19308

The type of a generic method is determined at compile time, which is why you can't set it using a variable. This is a key difference between generic programming and type reflection.

Upvotes: 1

David M
David M

Reputation: 72860

Only using the methods of the System.Reflection namespace, which really isn't worth it for the effort you're trying to save.

Upvotes: 2

Related Questions