From: Travis Parks on
Hello:

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.

Thanks,
Travis Parks
From: Peter Duniho on
Travis Parks wrote:
> Hello:
>
> 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? [...]

You need to be more specific. What is the context? A full-trust
application should have complete access to type members through
reflection, provided you are passing the appropriate binding flags.

If for some reason your assembly has restrictions on reflection, you may
be able to use the [InternalsVisibleTo] attribute to allow your dynamic
assembly to have access to the internals of your main assembly.

Personally, I would look for a solution that somehow avoids the need for
the dynamic types to have to call the factory directly. After all,
there's some approved way for other code to access the factory, directly
or indirectly, right? If the dynamic types went through the same
mechanism, they shouldn't need any more access to the assembly members
than any other client code would.

But barring that, you should be able to get the reflection to work fine.
If the above doesn't provide enough information, then provide a
concise-but-complete code example that reliably demonstrates the issue.

Pete
From: Travis Parks on
On Jun 6, 2:56 pm, Peter Duniho <NpOeStPe...(a)NnOwSlPiAnMk.com> wrote:
> Travis Parks wrote:
> > Hello:
>
> > 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? [...]
>
> You need to be more specific.  What is the context?  A full-trust
> application should have complete access to type members through
> reflection, provided you are passing the appropriate binding flags.
>
> If for some reason your assembly has restrictions on reflection, you may
> be able to use the [InternalsVisibleTo] attribute to allow your dynamic
> assembly to have access to the internals of your main assembly.
>
> Personally, I would look for a solution that somehow avoids the need for
> the dynamic types to have to call the factory directly.  After all,
> there's some approved way for other code to access the factory, directly
> or indirectly, right?  If the dynamic types went through the same
> mechanism, they shouldn't need any more access to the assembly members
> than any other client code would.
>
> But barring that, you should be able to get the reflection to work fine.
>   If the above doesn't provide enough information, then provide a
> concise-but-complete code example that reliably demonstrates the issue.
>
> Pete

The unfortunate thing is that code using System.Reflection.Emit is
rarely concise. Outside of my dynamically generated classes, the only
other code that knows about the factory is code in the same DLL. It is
not like my factory is dynamically generated. I suppose I could give
you a code snippet. It is the factory class that generates
IEqualityComparers. It uses type IMetaMapping to provide information
about the type the comparer is being made for. In my situation, I am
creating an IEqualityComparer for the primary key fields of types.

// EqualityComparerRegistry.cs
using System;
using System.Reflection.Emit;
using System.Reflection;

namespace Earthworm
{
/// <summary>
/// Provides access to a single repository of dynamically
generated IEqualityComparers.
/// </summary>
internal static class EqualityComparerRegistry
{
private readonly static AssemblyBuilder _assemblyBuilder;
private readonly static ModuleBuilder _moduleBuilder;

/// <summary>
/// Initializes the AssemblyBuilder and the ModuleBuilder.
/// </summary>
static EqualityComparerRegistry()
{
AssemblyName assemblyName = new
AssemblyName("Earthworm.EqualityComparers");
_assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.RunAndCollect);
_moduleBuilder =
_assemblyBuilder.DefineDynamicModule("EarthwormEqualityComparers");
}

/// <summary>
/// Gets the dynamic module to add types to.
/// </summary>
public static ModuleBuilder Module
{
get { return _moduleBuilder; }
}
}
}

// EqualityComparerFactory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection;
using Earthworm.Properties;

namespace Earthworm
{
/// <summary>
/// Creates IEqualityComparers that use the unique identifiers of
/// objects to determine equality.
/// </summary>
public sealed class EqualityComparerFactory
{
private readonly MetaMappingLookup _lookup;
private readonly Dictionary<Type, object> _cache;

/// <summary>
/// Creates a new EqualityComparerFactory.
/// </summary>
/// <param name="lookup">Provides information about the
uniquely identifying fields.</param>
public EqualityComparerFactory(MetaMappingLookup lookup)
{
_lookup = lookup;
_cache = new Dictionary<Type, object>();
}

/// <summary>
/// Creates a IEqualityComparer based on the type's unique
identifiers.
/// </summary>
/// <typeparam name="T">The type of the object to create the
comparer for.</typeparam>
/// <returns>The generated IEqualityComparer.</returns>
public IEqualityComparer<T> CreateComparer<T>(bool
holdHierachy)
{
object comparer;
if (!_cache.TryGetValue(typeof(T), out comparer))
{
IMetaMapping mapping = _lookup.GetMapping(typeof(T));
if (mapping == null)
{
return EqualityComparer<T>.Default;
}
IMemberMapping[] memberMappings =
mapping.MemberMappings.ToArray();
if (memberMappings.Length == 0)
{
return EqualityComparer<T>.Default;
}
IMemberMapping[] primaryKeyMappings =
memberMappings.Where(member => member.IsPrimaryKey).ToArray();
if (primaryKeyMappings.Length != 0)
{
memberMappings = primaryKeyMappings;
}
string typeName = typeof(T).Name + "EqualityComparer"
+ Guid.NewGuid().ToString("N");
TypeBuilder typeBuilder =
EqualityComparerRegistry.Module.DefineType(typeName,
TypeAttributes.Public | TypeAttributes.Sealed);

typeBuilder.AddInterfaceImplementation(typeof(IEqualityComparer<T>));

typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);

FieldInfo fieldInfo =
typeBuilder.DefineField("_factory", typeof(EqualityComparerFactory),
FieldAttributes.Private);

defineEquals<T>(typeBuilder, memberMappings,
fieldInfo, holdHierachy);
defineGetHashCode<T>(typeBuilder, memberMappings,
fieldInfo, holdHierachy);

Type type = typeBuilder.CreateType();
comparer = Activator.CreateInstance(type);
type.GetField(fieldInfo.Name, BindingFlags.NonPublic |
BindingFlags.Instance).SetValue(comparer, this);
_cache[typeof(T)] = comparer;
}
return (IEqualityComparer<T>)comparer;
}

private void defineEquals<T>(TypeBuilder typeBuilder,
IMemberMapping[] mappings, FieldInfo fieldInfo, bool holdHierachy)
{
MethodInfo equalInfo =
typeof(IEqualityComparer<T>).GetMethod("Equals");
MethodBuilder equals = buildMethod(typeBuilder,
equalInfo);
ILGenerator generator = equals.GetILGenerator();
LocalBuilder result =
generator.DeclareLocal(typeof(Int32));
Label endOfMethod = generator.DefineLabel();

if (holdHierachy)
{
MethodInfo getTypeInfo =
typeof(Object).GetMethod("GetType");
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Callvirt, getTypeInfo);
generator.Emit(OpCodes.Ldarg_2);
generator.Emit(OpCodes.Callvirt, getTypeInfo);
generator.Emit(OpCodes.Ceq);
generator.Emit(OpCodes.Brfalse, endOfMethod);
}

MethodInfo objectEquals =
typeof(Object).GetMethod("Equals", BindingFlags.Static |
BindingFlags.Public);
MethodInfo createComparerMethod =
typeof(EqualityComparerFactory).GetMethod("CreateComparer");
foreach (IMemberMapping mapping in mappings)
{
if (_lookup.Contains(mapping.MemberType))
{
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, fieldInfo);
generator.Emit(OpCodes.Ldc_I4_0); // false
MethodInfo genericCreateComparerMethod =
createComparerMethod.MakeGenericMethod(new Type[]
{ mapping.MemberType });
generator.Emit(OpCodes.Callvirt,
genericCreateComparerMethod);
generator.Emit(OpCodes.Ldarg_1);
emitMemberValue(generator, mapping);
generator.Emit(OpCodes.Ldarg_2);
emitMemberValue(generator, mapping);
Type comparerType =
typeof(IEqualityComparer<>).MakeGenericType(mapping.MemberType);
MethodInfo equalsMethod =
comparerType.GetMethod("Equals", new Type[] { mapping.MemberType,
mapping.MemberType });
generator.Emit(OpCodes.Callvirt, equalsMethod);
}
else
{
generator.Emit(OpCodes.Ldarg_1);
emitMemberValue(generator, mapping);
if (mapping.MemberType.IsValueType)
{
generator.Emit(OpCodes.Box,
mapping.MemberType);
}
generator.Emit(OpCodes.Ldarg_2);
emitMemberValue(generator, mapping);
if (mapping.MemberType.IsValueType)
{
generator.Emit(OpCodes.Box,
mapping.MemberType);
}
generator.Emit(OpCodes.Call, objectEquals);
}
generator.Emit(OpCodes.Brfalse, endOfMethod);
}

generator.Emit(OpCodes.Ldc_I4, 1);
generator.Emit(OpCodes.Stloc, result); // if we get this
far, we know we are equal
generator.MarkLabel(endOfMethod);
generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Ret);
}

private void defineGetHashCode<T>(TypeBuilder typeBuilder,
IMemberMapping[] mappings, FieldInfo fieldInfo, bool holdHierachy)
{
MethodInfo getHashCodeInfo =
typeof(IEqualityComparer<T>).GetMethod("GetHashCode");
MethodBuilder getHashCode = buildMethod(typeBuilder,
getHashCodeInfo);
ILGenerator generator = getHashCode.GetILGenerator();
LocalBuilder result =
generator.DeclareLocal(typeof(Int32));

MethodInfo objectGetHashCode =
typeof(Object).GetMethod("GetHashCode");

if (holdHierachy)
{
MethodInfo getTypeInfo =
typeof(Object).GetMethod("GetType");
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Callvirt, getTypeInfo);
generator.Emit(OpCodes.Callvirt, objectGetHashCode);
generator.Emit(OpCodes.Stloc, result);
}

MethodInfo createComparerMethod =
typeof(EqualityComparerFactory).GetMethod("CreateComparer");
foreach (IMemberMapping mapping in mappings)
{
Label skip = generator.DefineLabel();
generator.Emit(OpCodes.Ldarg_1);
emitMemberValue(generator, mapping);
generator.Emit(OpCodes.Brfalse, skip);
if (_lookup.Contains(mapping.MemberType))
{
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, fieldInfo);
generator.Emit(OpCodes.Ldc_I4_0); // false
MethodInfo genericCreateComparerMethod =
createComparerMethod.MakeGenericMethod(new Type[]
{ mapping.MemberType });
generator.Emit(OpCodes.Callvirt,
genericCreateComparerMethod);
generator.Emit(OpCodes.Ldarg_1);
emitMemberValue(generator, mapping);
Type comparerType =
typeof(IEqualityComparer<>).MakeGenericType(new Type[]
{ mapping.MemberType });
MethodInfo comparerGetHashCode =
comparerType.GetMethod("GetHashCode", new Type[]
{ mapping.MemberType });
generator.Emit(OpCodes.Callvirt,
comparerGetHashCode);
}
else
{
generator.Emit(OpCodes.Ldarg_1);
emitMemberValue(generator, mapping);
if (mapping.MemberType.IsValueType)
{
generator.Emit(OpCodes.Box,
mapping.MemberType);
}
generator.Emit(OpCodes.Callvirt,
objectGetHashCode);
}
generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Xor);
generator.Emit(OpCodes.Stloc, result);
generator.MarkLabel(skip);
}

generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Ret);
}

private static MethodBuilder buildMethod(TypeBuilder
typeBuilder, MethodInfo methodInfo)
{
MethodAttributes attributes = methodInfo.Attributes;
attributes &= ~(MethodAttributes.VtableLayoutMask |
MethodAttributes.Abstract);
MethodBuilder methodBuilder =
typeBuilder.DefineMethod(methodInfo.Name,
attributes,
methodInfo.CallingConvention,
methodInfo.ReturnType,
methodInfo.GetParameters().Select(parameter =>
parameter.ParameterType).ToArray());
return methodBuilder;
}

private static void emitMemberValue(ILGenerator generator,
IMemberMapping mapping)
{
if (mapping.MemberInfo.MemberType == MemberTypes.Field)
{
generator.Emit(OpCodes.Ldfld,
(FieldInfo)mapping.MemberInfo);
}
else
{
PropertyInfo propertyInfo =
(PropertyInfo)mapping.MemberInfo;
MethodInfo getterInfo = propertyInfo.GetGetMethod();
generator.Emit(OpCodes.Callvirt, getterInfo);
}
}
}
}
From: Arne Vajhøj on
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
From: Travis Parks on
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