From: Travis Parks on
On Jun 6, 10:00 pm, Travis Parks <jehugalea...(a)gmail.com> wrote:
> On Jun 6, 7:54 pm, Arne Vajhøj <a...(a)vajhoej.dk> wrote:
>
>
>
>
>
> > On 06-06-2010 12:12, Travis Parks wrote:
>
> > > I have an internal factory class with methods I want to call from
> > > another DLL using reflection. However, trying to do so results in a
> > > MethodAccessException.
>
> > > I am assuming this is because library vendors don't want people
> > > accessing internal members. Is there a way around this?
>
> > > In my situation, I have a factory class that generates
> > > IEqualityComparer<T>  types at runtime using System.Reflection.Emit..
> > > The comparers can be recursive, meaning that they can rely on other
> > > dynamically generated comparers. In order to do so, they need to call
> > > methods on the factory.
>
> > > What are my options? My factory has to be internal or public. I'd
> > > rather avoid exposing this class if I can. I am hoping there is some
> > > flag or attribute that tells the runtime to relax.
>
> > How do you attempt to call the method?
>
> > Normally the accessibility rules does not apply to reflection.
>
> > The following code runs:
>
> > using System;
> > using System.Reflection;
>
> > namespace E
> > {
> >      public class Test
> >      {
> >          private void NoAccessMethod()
> >          {
> >              Console.WriteLine("What happended here?");
> >          }
> >      }
> >      public class Program
> >      {
> >          public static void Main(string[] args)
> >          {
> >              Test o = new Test();
> >              //o.NoAccessMethod();
> >              MethodInfo mi = o.GetType().GetMethod("NoAccessMethod",
> > BindingFlags.DeclaredOnly | BindingFlags.NonPublic |
> > BindingFlags.Instance, null, new Type[0], null);
> >              mi.Invoke(o, new object[0]);
> >          }
> >      }
>
> > }
>
> > Arne- Hide quoted text -
>
> > - Show quoted text -
>
> Instead of private, I'm calling a method in an internal class. That is
> the only difference.
>
> MethodInfo createComparerMethod =
> typeof(EqualityComparerFactory).GetMethod("CreateComparer"); // takes
> T
> generator.Emit(OpCodes.Ldarg_0);
> generator.Emit(OpCodes.Ldfld, fieldInfo); // each comparer holds a
> reference to the factory, which is supposed to be internal
> generator.Emit(OpCodes.Ldc_I4_0); // false
> MethodInfo genericCreateComparerMethod =
> createComparerMethod.MakeGenericMethod(new Type[]
> { mapping.MemberType });
> generator.Emit(OpCodes.Callvirt, genericCreateComparerMethod);
>
> Could the fact that the method is generic make a difference? The
> factory itself is nongeneric, but the CreateComparer method takes a T.
>
> I know from experience calling non-public methods is perfectly valid.
> I have only run into this issue when doing stuff with
> System.Reflection.Emit. Perhaps dynamically generated types have
> access restrictions? Beats me.
>
> Thanks,
> Travis Parks- Hide quoted text -
>
> - Show quoted text -

Also calling a method on an internal class works using plain jane
reflection, too. Why the difference with Emit?

// load an internal class from another assembly
Assembly assembly = Assembly.LoadFrom("OtherLibrary.dll");
Type type = assembly.GetType("OtherLibrary.Class1");
object class1 = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("DoSomething");
methodInfo.Invoke(class1, null);
From: Peter Duniho on
Travis Parks wrote:
> [...]
> Also calling a method on an internal class works using plain jane
> reflection, too. Why the difference with Emit?

Well, that's certainly the crux of the question. I don't think
dynamically generated code should in fact be different from statically
compiled code. That suggests that the error you're getting is due to
some other difference that's being obscured by the mechanism of
dynamically generating the code.

If I have some time later, I'll take a look at the code sample you
posted. I'm not actually an expert in dynamically generated code, but
sometimes all it takes is a second set of eyes looking at the problem.

Pete
From: Peter Duniho on
Peter Duniho wrote:
> [...]
> If I have some time later, I'll take a look at the code sample you
> posted. I'm not actually an expert in dynamically generated code, but
> sometimes all it takes is a second set of eyes looking at the problem.

Actually, I took a preliminary look, and there are two problems with the
code example that was supposed to be concise and complete: it's neither
concise, nor complete.

You should post the bare minimum required to demonstrate the problem.
In your case, that means you need only generate a type with a single
member that is trying to access the internal member in question (or
rather, a minimal internal member, just whatever is required to actually
demonstrate the issue).

You also should post a code example that can be compiled and run without
any additional work. For simple examples, I and others are reasonably
good at just inspecting the code and finding the problem. But I'm sure
you'd agree that dynamic code generation does not fall into any
reasonable definition of "simple".

You may find someone else willing to try to find the problem in just the
code you posted. But others, including myself, won't bother to look at
all unless it's convenient to actually compile and run the code so that
it can be inspected in a debugger.

Pete
From: Travis Parks on
On Jun 6, 11:00 pm, Peter Duniho <NpOeStPe...(a)NnOwSlPiAnMk.com> wrote:
> Peter Duniho wrote:
> > [...]
> > If I have some time later, I'll take a look at the code sample you
> > posted.  I'm not actually an expert in dynamically generated code, but
> > sometimes all it takes is a second set of eyes looking at the problem.
>
> Actually, I took a preliminary look, and there are two problems with the
> code example that was supposed to be concise and complete: it's neither
> concise, nor complete.
>
> You should post the bare minimum required to demonstrate the problem.
> In your case, that means you need only generate a type with a single
> member that is trying to access the internal member in question (or
> rather, a minimal internal member, just whatever is required to actually
> demonstrate the issue).
>
> You also should post a code example that can be compiled and run without
> any additional work.  For simple examples, I and others are reasonably
> good at just inspecting the code and finding the problem.  But I'm sure
> you'd agree that dynamic code generation does not fall into any
> reasonable definition of "simple".
>
> You may find someone else willing to try to find the problem in just the
> code you posted.  But others, including myself, won't bother to look at
> all unless it's convenient to actually compile and run the code so that
> it can be inspected in a debugger.
>
> Pete

Concise and complete:

using System;
using System.Reflection;
using System.Reflection.Emit;

namespace TestCS
{
class Program
{
static void Main(string[] args)
{
AssemblyName assemblyName = new AssemblyName("TestAssm");
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder moduleBuilder =
assemblyBuilder.DefineDynamicModule("TestAssm.Module");
TypeBuilder typeBuilder =
moduleBuilder.DefineType("TestAssm.DynaType", TypeAttributes.Sealed |
TypeAttributes.Public);

typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
MethodBuilder methodBuilder =
typeBuilder.DefineMethod("DynaMethod",
MethodAttributes.Public,
CallingConventions.HasThis |
CallingConventions.Standard,
typeof(void),
Type.EmptyTypes);
ILGenerator generator = methodBuilder.GetILGenerator();
ConstructorInfo ctorInfo =
typeof(Internal).GetConstructor(Type.EmptyTypes);
generator.Emit(OpCodes.Newobj, ctorInfo);
MethodInfo doSomethingInfo =
typeof(Internal).GetMethod("DoSomething");
generator.Emit(OpCodes.Callvirt, doSomethingInfo);
generator.Emit(OpCodes.Ret);
Type dynaType = typeBuilder.CreateType();
object instance = Activator.CreateInstance(dynaType);
MethodInfo dynaMethod = dynaType.GetMethod("DynaMethod");
dynaMethod.Invoke(instance, null);
}
}

internal class Internal
{
public void DoSomething()
{
}
}
}

Thanks for looking at this. It is the simplest reproduction of the
issue I could think of. I am hoping my issue is really simple.
From: Arne Vajhøj on
On 07-06-2010 19:02, Travis Parks wrote:
> On Jun 6, 11:00 pm, Peter Duniho<NpOeStPe...(a)NnOwSlPiAnMk.com> wrote:
>> Peter Duniho wrote:
>>> [...]
>>> If I have some time later, I'll take a look at the code sample you
>>> posted. I'm not actually an expert in dynamically generated code, but
>>> sometimes all it takes is a second set of eyes looking at the problem.
>>
>> Actually, I took a preliminary look, and there are two problems with the
>> code example that was supposed to be concise and complete: it's neither
>> concise, nor complete.
>>
>> You should post the bare minimum required to demonstrate the problem.
>> In your case, that means you need only generate a type with a single
>> member that is trying to access the internal member in question (or
>> rather, a minimal internal member, just whatever is required to actually
>> demonstrate the issue).
>>
>> You also should post a code example that can be compiled and run without
>> any additional work. For simple examples, I and others are reasonably
>> good at just inspecting the code and finding the problem. But I'm sure
>> you'd agree that dynamic code generation does not fall into any
>> reasonable definition of "simple".
>>
>> You may find someone else willing to try to find the problem in just the
>> code you posted. But others, including myself, won't bother to look at
>> all unless it's convenient to actually compile and run the code so that
>> it can be inspected in a debugger.
>
> Concise and complete:
>
> using System;
> using System.Reflection;
> using System.Reflection.Emit;
>
> namespace TestCS
> {
> class Program
> {
> static void Main(string[] args)
> {
> AssemblyName assemblyName = new AssemblyName("TestAssm");
> AssemblyBuilder assemblyBuilder =
> AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
> AssemblyBuilderAccess.RunAndCollect);
> ModuleBuilder moduleBuilder =
> assemblyBuilder.DefineDynamicModule("TestAssm.Module");
> TypeBuilder typeBuilder =
> moduleBuilder.DefineType("TestAssm.DynaType", TypeAttributes.Sealed |
> TypeAttributes.Public);
>
> typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
> MethodBuilder methodBuilder =
> typeBuilder.DefineMethod("DynaMethod",
> MethodAttributes.Public,
> CallingConventions.HasThis |
> CallingConventions.Standard,
> typeof(void),
> Type.EmptyTypes);
> ILGenerator generator = methodBuilder.GetILGenerator();
> ConstructorInfo ctorInfo =
> typeof(Internal).GetConstructor(Type.EmptyTypes);
> generator.Emit(OpCodes.Newobj, ctorInfo);
> MethodInfo doSomethingInfo =
> typeof(Internal).GetMethod("DoSomething");
> generator.Emit(OpCodes.Callvirt, doSomethingInfo);
> generator.Emit(OpCodes.Ret);
> Type dynaType = typeBuilder.CreateType();
> object instance = Activator.CreateInstance(dynaType);
> MethodInfo dynaMethod = dynaType.GetMethod("DynaMethod");
> dynaMethod.Invoke(instance, null);
> }
> }
>
> internal class Internal
> {
> public void DoSomething()
> {
> }
> }
> }
>
> Thanks for looking at this. It is the simplest reproduction of the
> issue I could think of. I am hoping my issue is really simple.

The problem is that you are not using reflection!

You are:

Main---(reflection)--->generated code---(regular call)--->Internal

And that fails.

Either change the accessability.

Or use reflection.

Arne