2014-10-10 1 views
1

Можно вызвать метод, который находится на «обычной» сборке из динамически построенной сборки?Выполнить метод на постоянной сборке из динамической сборки

Например, сборка Б динамически строится (через Emit) от узла А и узла B должен вызвать статический метод, который определен на сборочном А.

public interface IMapper 
{ 
    void Map(); 
} 

public void CreateDynamic() { 
    AppDomain app = AppDomain.CurrentDomain; 
    AssemblyName name = new AssemblyName("assemblyB"); 
    AssemblyBuilder assembly = app 
    .DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); 
    ModuleBuilder module = assembly 
    .DefineDynamicModule(assembly.GetName().Name, "b.dll"); 

    TypeBuilder type = module.DefineType("MyType", 
    TypeAttributes.Public | 
     TypeAttributes.Class | 
     TypeAttributes.AutoClass | 
     TypeAttributes.AutoLayout, null, new[] {typeof (IMapper)}); 

    MethodBuilder method = type 
    .DefineMethod("Map", 
     MethodAttributes.Public | 
     MethodAttributes.HideBySig | 
     MethodAttributes.Virtual); 

    ILGenerator il = method.GetILGenerator(); 

    Func<int, TimeSpan> func = i => TimeSpan.FromSeconds(i); 

    il.Emit(OpCodes.Ldc_I4_S, 10); 
    il.Emit(OpCodes.Callvirt, func.Method); 
    il.Emit(OpCodes.Ret); 

    Type t = type.CreateType(); 

    IMapper mapper = (IMapper) Activator.CreateInstance(t); 
    mapper.Map(); 
} 

Когда метод Карта выполняется в MissingMethodExcetion бросается, и теперь я не причина этого.

+0

Предоставить образец кода и/или проверить эту http://stackoverflow.com/questions/11908156/call-static-method-with-reflection –

ответ

1

Ниже строки вызывает метод private static, который будет создан в классе во время компиляции.

Func<int, TimeSpan> func = i => TimeSpan.FromSeconds(i); 

То, что вы пытаетесь сделать, становится чем-то вроде этого.

public class TestClass { 
    private static TimeSpan CompilerGeneratedMethod(int i) { 
     return TimeSpan.FromSeconds(i); 
    } 

    public void CreateDynamic() { 
     // Other codes... 

     var methodInfo = typeof(TestClass).GetMethod("CompilerGeneratedMethod", BindingFlags.Static | BindingFlags.NonPublic); 

     il.Emit(OpCodes.Ldc_I4_S, 10); 
     il.Emit(OpCodes.Callvirt, methodInfo); 
     il.Emit(OpCodes.Ret); 

     // Other codes... 
    } 
} 

Теперь мы только что создали класс в AssemblyB, который пытается вызвать метод private static в другой сборке. Если он был написан непосредственно на C#, он может выглядеть примерно так.

public class MyType : IMapper { 
    public void Map() { 
     TestClass.CompilerGeneratedMethod(10); 
    } 
} 

Поскольку CompilerGeneratedMethod является private она не может быть доступна. Поэтому, вместо использования lamda, давайте попробуем использовать реальный объявленный метод public.

public class TestClass { 
    public static TimeSpan HandWrittenMethod(int i) { 
     return TimeSpan.FromSeconds(i); 
    } 

    public void CreateDynamic() { 
     // Other codes... 

     var methodInfo = typeof(TestClass).GetMethod("HandWrittenMethod"); 

     il.Emit(OpCodes.Ldc_I4_S, 10); 
     il.Emit(OpCodes.Callvirt, methodInfo); 
     il.Emit(OpCodes.Ret); 

     // Other codes... 
    } 
} 

Теперь у нас есть одна небольшая проблема. Мы пытаемся вызвать статический метод, используя Callvirt, который следует использовать для методов поздней привязки. Вместо Callvirt мы должны использовать только Call.

il.Emit(OpCodes.Call, methodInfo); 
+0

я не могу создать настоящий публичный метод, так как преобразователь предназначен для использования внешними библиотеками, поэтому имя метода не известно заранее. – nohros