OK, I know what do to with you. Even if you are were not convinced by my clear example of
System.Collection.Generic.Dictionary
(you started to argument that the generic parameters are not constrained), I'll better show you a right method of research which you can use by yourself and remove all doubts. You did not provide a comprehensive complete sample, so I'll do it for you.
I'll start with some minimalistic C# samples, with two generic parameters, and with generic parameter constraints:
using System;
namespace MultipleGenericParameters {
public class SomethingDisposable : System.IDisposable {
void System.IDisposable.Dispose() { }
}
public class Test {
public static void GenericMethod<First, Second>(First first, Second second)
where First: System.IDisposable
where Second: new() { }
public static void GenericMethodCaller() {
GenericMethod<SomethingDisposable, System.Text.StringBuilder>(
new SomethingDisposable(),
new System.Text.StringBuilder());
}
}
class Program {
static void Main(string[] args) {
}
}
}
Clear enough, isn't it?
For the rest of it, we will need an open-source tool, ILSpy:
http://ilspy.net/[
^],
http://en.wikipedia.org/wiki/.NET_Reflector[
^].
Get it, open, but better compile by yourself. Reflector, presently commercial, can also be used, if you have this product.
Compile the above code and decompile it to VB.NT. You will get:
Imports System
Imports System.Text
Namespace MultipleGenericParameters
Public Class SomethingDisposable
Implements IDisposable
Sub Dispose() Implements IDisposable.Dispose
End Sub
End Class
Public Class Test
Public Shared Sub GenericMethod(Of First As IDisposable, Second As New)(first As First, second As Second)
End Sub
Public Shared Sub GenericMethodCaller()
Test.GenericMethod(Of SomethingDisposable, StringBuilder)(New SomethingDisposable(), New StringBuilder())
End Sub
End Class
End Namespace
As you can see, two generic parameters with generic parameter constraint fit nicely in VB.NET. Now, you can compile it, add some test code, run it — I bet it works.
You an even "invent" more arguments against VB.NET, but now you have no excuses: you should compile your code, decompile it and make sure it is valid in the different language. Moreover, you can test, and, importantly, decompile it to CIL to IL:
MultipleGenericParameters.Test
:
.class public auto ansi beforefieldinit MultipleGenericParameters.Test
extends [mscorlib]System.Object
{
.method public hidebysig static
void GenericMethod<([mscorlib]System.IDisposable) First, .ctor Second> (
!!First first,
!!Second second
) cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ret
}
.method public hidebysig static
void GenericMethodCaller () cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: newobj instance void MultipleGenericParameters.SomethingDisposable::.ctor()
IL_0006: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
IL_000b: call void MultipleGenericParameters.Test::GenericMethod<class MultipleGenericParameters.SomethingDisposable, class [mscorlib]System.Text.StringBuilder>(!!0, !!1)
IL_0010: nop
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
}
}
MultipleGenericParameters.SomethingDisposable
:
.class public auto ansi beforefieldinit MultipleGenericParameters.SomethingDisposable
extends [mscorlib]System.Object
implements [mscorlib]System.IDisposable
{
.method private final hidebysig newslot virtual
instance void System.IDisposable.Dispose () cil managed
{
.override method instance void [mscorlib]System.IDisposable::Dispose()
.maxstack 8
IL_0000: nop
IL_0001: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
}
}
You can even make a round trip: compiler both VB.NET and C# projects, make sure they compile, decompile into IL. Try to find differences. In this very case, you won't.
Is that finally end of story? If not, take
your code and repeat the procedure.
[EDIT #1]
I cannot believe I advocate VB.NET! Yes, this language probably has no chance to become a standard, it has a heavy legacy of some really moronic predecessor "languages" (quotation marks intended), it is hardly taken seriously by serious developers; and I never allow myself to install it on my computers…
But — it's important to be fair and keep to pure facts. Generics in this language is not a failure. :-)
[EDIT #2]
Thank you for clarification. I got your updated, complete code. First of all, C# comments
could rather read "
of course it should not compile". :-)
Now, I compiled all your code converted to VB.NET and got as expected:
Imports System
Namespace WildWildWest
Public Module Extensions
<System.Runtime.CompilerServices.ExtensionAttribute()>
Public Function Load(Of TGun As Gun(Of TAmmo), TAmmo As Ammo)
(ammo As TAmmo) As TGun
Dim gun As TGun = Activator.CreateInstance(Of TGun)()
gun.Ammo = ammo
Return gun
End Function
End Module
Public Class Test
Private Sub SomeMethod()
Dim ammo As BigAmmo = New BigAmmo()
Dim gun As BigGun = ammo.Load(Of BigGun, BigAmmo)()
End Sub
End Class
End Namespace
Any problem with that?
Good luck,
—SA