我建议不要返回接口,而是将委托作为适配器返回。
public static TFunc CreateAdapter<TFunc>(Type staticClass, string methodName)
{
var method = staticClass.GetMethod(methodName,
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
var methodParameters = new ParameterExpression[parameterTypes.Length];
for (int i = 0; i < parameterTypes.Length; i++)
{
methodParameters[i] = Expression.Parameter(parameterTypes[i], "p" + i);
}
var lambda = Expression.Lambda<TFunc>(
Expression.Call(null, method, methodParameters), methodParameters);
return lambda.Compile();
}
并像这样使用它:
var adapter = CreateAdapter<Func<int, int, int>>(typeof(CalculatorStatic),
nameof(CalculatorStatic.ComplexCalculation));
Console.WriteLine(adapter(1, 2));
如果你真的-真的想使用接口(因为它有不止一种方法),你应该为每个接口创建一个适配器工厂:
public ICalculator CreateAdapter(Type staticClassType)
{
return new CalculatorAdapter(staticClassType);
}
// todo: factory methods for other interfaces, too
还有计算器适配器:
private class CalculatorAdapter: ICalculator
{
private readonly Func<int, int, int> complexCalculationAdapter;
internal CalculatorAdapter(Type staticClassType)
{
complexCalculationAdapter = CreateAdapter<Func<int, int, int>>(staticClassType,
nameof(ICalculator.ComplexCalculation));
// TODO: initialize the other fields if there are more interface methods
}
public int ComplexCalculation(int a, int b)
{
return complexCalculationAdapter(a, b);
}
}
更新
如果你真的想为所有接口创建一个方法,你应该生成一个动态类。
请注意,这个例子并不完美。您应该缓存动态程序集和模块,而不是总是创建一个新的,如果您调用 ref/out 参数,您应该将它们分配回来,等等。但也许意图很明确。代码提示:编译一个直接实现接口的代码,然后反汇编它,看看在生成器中要发出什么代码。
public static T CreateAdapter<T>(Type staticClassType)
{
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(typeof(T).Name + "Adapter"),
AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule(typeof(T).Name + "Adapter.dll");
// public class TAdapter : T
TypeBuilder tb = mb.DefineType(typeof(T).Name + "Adapter", TypeAttributes.Public | TypeAttributes.Class,
typeof(object), new Type[] { typeof(T) });
// creating methods
foreach (var methodInfo in typeof(T).GetMethods())
{
var parameters = methodInfo.GetParameters();
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
var method = tb.DefineMethod(methodInfo.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
methodInfo.ReturnType, parameterTypes);
// adding parameters
for (int i = 0; i <parameters.Length; i++)
{
method.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name);
}
// calling the static method from the body and returning its result
var staticMethod = staticClassType.GetMethod(methodInfo.Name, parameterTypes);
var code = method.GetILGenerator();
for (int i = 0; i < parameters.Length; i++)
{
code.Emit(OpCodes.Ldarg_S, i + 1);
}
code.Emit(OpCodes.Call, staticMethod);
code.Emit(OpCodes.Ret);
}
return (T)Activator.CreateInstance(tb.CreateType());
}
}