开发者

Calling a generic function in VB.NET / C#

开发者 https://www.devze.com 2023-01-01 17:58 出处:网络
Question: I want to call a generic function, defined as: Public Shared Function DeserializeFromXML(Of T)(Optional ByRef strFileNameAndPath As String = Nothing) As T

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.XM开发者_如何学GoLserializeLDAPconfig.DeserializeFromXML(Of XMLserialization.cConfiguration)()

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


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)()


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
}


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


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.


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.


[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.

0

精彩评论

暂无评论...
验证码 换一张
取 消