This project has moved. For the latest updates, please go here.

MethodAccessException

Topics: Developer Forum
May 24, 2007 at 12:50 PM
Hi,

I am getting MethodAccessException when I use DynamicComparer to compare classes using some property which is declared at the base-class level.

The base class is abstract generic class BDORoot<T> and has properties like ID, DateCreated etc.. Derived classes inherit from it like: class CurrencyBDO : BDORoot<CurrencyBDO>.

When I use DynamicComparer to sort by (for example) Name property which is declared in CurrencyBDO everything works fine. But when I try to sort by some property declared in BDORoot like ID or DateCreated it throws MethodAccessException ("cannot invoke get_ID() method") during comparer.Invoke(x, y) call. I run it locally in Full trust so I do not understand why this happens. All that properties and classes are public.

Do you have any idea what might be wrong? My code or something in DynamicEmit class?

BTW: Thanks Mark for great Dynamic Reflection Library .

Vlado.
Coordinator
May 25, 2007 at 4:48 AM
Any chance you could give me a minimal reproduction of the issue in code? I can fix it much faster if I'm sure I'm addressing your actual issue.
May 25, 2007 at 7:26 AM
Hi Marc, here is very simple minimal reproduction:

using System;
using System.Collections.Generic;
using System.Text;
using Phydeaux.Utilities;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// get the list
List<CountryBDO> list = CountryBDO.getAllBDOs();
}

}

// base class
public abstract class BDORoot<TBDO>
{
private long? _ID;
public long? ID
{
get { return _ID; }
set { _ID = value; }
}
}

// derived class
public class CountryBDO : BDORoot<CountryBDO>
{
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}

public static List<CountryBDO> getAllBDOs()
{

List<CountryBDO> list = new List<CountryBDO>();
CountryBDO c1 = new CountryBDO();
c1.ID = 100;
c1.Name = "USA";
list.Add(c1);
CountryBDO c2 = new CountryBDO();
c2.ID = 50;
c2.Name = "Slovakia";
list.Add(c2);
CountryBDO c3 = new CountryBDO();
c3.ID = 150;
c3.Name = "Vanuatu";
list.Add(c3);

//works
list.Sort(new DynamicComparer<CountryBDO>("Name"));

//throws exception
list.Sort(new DynamicComparer<CountryBDO>("ID"));

return list;
}
}
}
May 25, 2007 at 1:49 PM
Hi. I found the solution. I changed Call method in DynamicEmit class to this:

public void Call(MethodInfo method)
{
if (method.IsFinal || !method.IsVirtual)
{
_ilGen.Emit(OpCodes.Call, method);
}
else
{
_ilGen.Emit(OpCodes.Callvirt, method);
}
}

Now everything works fine.

According to this http://blogs.msdn.com/haibo_luo/archive/2006/08/13/698719.aspx
EmitCall is mainly for varargs methods and you can (should) use Emit when you do not use varargs.
I do not understand MSIL but I might be a bug in EmitCall or I don't know.

Have a nice day.

Vlado
May 25, 2007 at 5:32 PM
OR another solution to this is to set skipVisibility parameter in DynamicMethod constructor to true:

DynamicMethod dm = new DynamicMethod("DynamicCompare"
, MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard,
typeof(int), new Type[] { typeof(T), typeof(T) }, typeof(T), true);
Coordinator
May 25, 2007 at 7:44 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Coordinator
May 25, 2007 at 8:01 PM
I've updated the code according to your suggestion (keeping the existing path intact for varargs methods) and added your test-case. Let me know if the current build does the trick and I'll drop a new release.
May 26, 2007 at 9:46 AM
Hi, of course, as expected, this new code (changeset 22961) works fine in my generic base class scenario too.

Vlado.