After some experimenting, I don't think it's an SRE bug; in fact, it's
easy to reproduce without System.Reflection.Emit. In my test class, I
have the following two IL lines:
1 - callvirt instance string class
ConsoleApplication19.GenericTestInterface`1<class
[mscorlib]System.Collections.Generic.List`1<string>>::GenericTestMethod<!!0>(!!0)
2 - ldtoken method instance string class
ConsoleApplication19.GenericTestInterface`1<class
[mscorlib]System.Collections.Generic.List`1<string>>::GenericTestMethod<!!0>(!!0)
Line 1 calls the method, line 2 loads its token into a
RuntimeMethodHandle. Line 1 works, line 2 gives the verification
error. When I look up the bytes in ILDASM, I can see that both lines
use exactly the same token. I believe if a callvirt with the token is
allowed, a ldtoken must be allowed as well - definitely looks like
another ldtoken bug in conjunction with generic methods (about the
fifth or something?).
I'll report that, after all, we're in a beta phase for Orcas. For the
time being, I can't really see a workaround, however. One could
replace the ldtoken with Type.GetMethod() in these cases, but this
would probably be a lot of work.
> The main issue is that I want to specify a base class constraint with a
> interface constraint on a method, but it doesn't generate them in the same
> order as the C# compiler does.
> The C# compiler generate <class>, <interfaces> while SRE generates them
> <interfaces>, <class>
> It doesn't matter in what order they are specified, as far as I can see.
As far as I can tell, the order in which the constraints are emitted
doesn't matter.
Fabian
Inside the generated proxy method.
> As far as I could track, the error occured when validating the
> GenericTestMethod.
> Did the error happened when you run the code or when the CLR verified it?
The error occurs when the generated assembly is verified. PEVerify
points to the following line in
GenericTestInterface`1ProxyXXX.GenericTestMethod:
IL_0011: ldtoken instance string class
[Castle.DynamicProxy.Tests]Castle.DynamicProxy.Tests.GenericTestInterface`1<class
[mscorlib]System.Collections.ObjectModel.Collection`1<string>>::GenericTestMethod<!!0>(!!0)
This is the ldtoken instruction which - IMO without reason - causes
the verification error.
I've reproduced the problem by disassembling a simple C# program, see
below, and adding a ldtoken instruction to it. Although the ldtoken
instruction uses the same token as the callvirt emitted by the C#
compiler, it yields the verification error.
Fabian
Sample:
using System;
using System.Collections.Generic;
class Program
{
static void Main ()
{
new Implementer ().GenericTestMethod (new List<string> ());
}
}
public interface GenericTestInterface<T> where T : IEnumerable<string>
{
string GenericTestMethod<T2> (T2 obj) where T2 : T;
}
public class Implementer : GenericTestInterface<List<string>>
{
public string GenericTestMethod<T2> (T2 obj) where T2: List<string>
{
GenericTestInterface<List<string>> ifc = this;
return ifc.GenericTestMethod<T2> (null);
}
}
Okay, I've been talking about the exception that you mentioned you got
after applying your patch. It's a VerificationException with the same
info PEVerify is reporting, therefore I'm sure it's because of the
ldtoken line I quoted earlier. Doesn't really matter whether it occurs
at runtime or in a specific verification step.
The other exception, which you fixed with your patch, has another
reason (GetParameterConstraints returning T instead of List<string>,
which, I believe, is on purpose, although it's awkward). But since you
fixed it I wasn't talking about it.
Fabian
I believe so. I don't see why the code should pass (PEVerify and
runtime) verification if the method identified by a token is called,
but yield an error when the same token is loaded.
> Also, you mentioned Type.GetMethod(), but that would give us the open
> method, can it help in any way?
Yes, I suppose we could close it by calling MakeGenericMethod (typeof
(T2)) from within the generated proxy method. However, I didn't try
it, and I'm not sure whether the use case is worth the effort.
Fabian