我很好奇是否可以在只有手头类型的情况下创建委托。 像这样:
var concreteType = DiscoverTypeInRuntime();
var methodName = "SomeNameIKnowInAdvance";
var methodInfo = concreteType.GetMethodInfo(methodName);
var dynamicallyConstructedFunc = DynamicallyConstructFunc(methodInfo)
委托应为
类型Func<ConcreteType>
更新:
事先不知道确切的类型。它是在程序运行期间发现的。代理不能是Func<object
类型,只允许Func<ConcreteType>
。
名称已知的方法是工厂方法,它返回ConcreteType
的实例,因此需要。
更新2:
我将在这里提供一些代码来解释用例。希望这会澄清这个问题:
public class LoginProviderBuilder : FakeBuilderBase<ILoginProvider>
{
private readonly Dictionary<string, string> _users = new Dictionary<string, string>();
private LoginProviderBuilder()
{
}
//...
}
public class Module : ProvidersModuleBase
{
protected override void OnRegisterProviders(IIocContainerRegistrator iocContainer)
{
base.OnRegisterProviders(iocContainer);
RegisterAllBuilders(iocContainer, LoginProviderBuilder.CreateBuilder);
RegisterAllBuilders(iocContainer, WarehouseProviderBuilder.CreateBuilder);
RegisterAllBuilders(iocContainer, EventsProviderBuilder.CreateBuilder);
}
}
protected void RegisterAllBuilders<TProvider>(IIocContainerRegistrator iocContainerRegistrator,
Func<FakeBuilderBase<TProvider>> defaultBuilderCreationFunc) where TProvider : class
{
var builders = BuildersCollectionContext.GetBuilders<TProvider>().ToArray();
if (builders.Length == 0)
{
RegistrationHelper.RegisterBuilder(iocContainerRegistrator, defaultBuilderCreationFunc());
}
else
{
foreach (var builder in builders)
{
RegistrationHelper.RegisterBuilder(iocContainerRegistrator, builder);
}
}
}
简而言之,手头的任务是动态发现所有符合条件的构建器类型,并自动注册它们,同时保留具体类型和现有泛型API。
如果此代码不清楚,您可以在此处找到示例解决方案: https://github.com/LogoFX/Samples.Specifications
答案 0 :(得分:3)
借助一些 Reflection ,你可以构建一个像这样的函数:
private Func<T> GetDelegateFromMethodName<T>(string methodName)
{
var type = typeof(T);
var method = type.GetMethods().FirstOrDefault(m => m.Name == methodName);
if (method == null)
{
throw new ArgumentException(nameof(methodName));
}
return (Func<T>) Delegate.CreateDelegate(typeof(Func<T>), method);
}
以下是一个示例用法:
var methodName = "SomeNameIKnowInAdvance";
var dynamicallyConstructedFunc = GetDelegateFromMethodName<ConcreteClass>(methodName);
请记住,这只适用于静态方法,如果你想让它适用于实例方法,你也需要传递一个实例:
private Func<T> GetDelegateFromMethodName<T>(T instance, string methodName)
{
var type = typeof(T);
var method = type.GetMethods().FirstOrDefault(m => m.Name == methodName);
if (method == null)
{
throw new ArgumentException(nameof(methodName));
}
return (Func<T>) Delegate.CreateDelegate(typeof(Func<T>), instance, method);
}
用法的一个示例是:
var methodName = "ConstructClass";
var dynamicallyConstructedFunc = GetDelegateFromMethodName<ConcreteClass>(new ConcreteClass(), methodName);
如果你不喜欢泛型,你也可以使用object
,但不会导致Func<ConcreteClass>
,你必须手动投射:
private Func<object> GetDelegateFromMethodName(object instance, string methodName)
{
var type = instance.GetType();
var method = type.GetMethods().FirstOrDefault(m => m.Name == methodName);
if (method == null)
{
throw new ArgumentException(nameof(methodName));
}
return (Func<object>) Delegate.CreateDelegate(typeof(Func<object>), instance, method);
}
private Func<object> GetDelegateFromMethodName(Type type, string methodName)
{
var method = type.GetMethods().FirstOrDefault(m => m.Name == methodName);
if (method == null)
{
throw new ArgumentException(nameof(methodName));
}
return (Func<object>)Delegate.CreateDelegate(typeof(Func<object>), method);
}
答案 1 :(得分:0)
您可以创建这样的委托 - 但您只能将其称为Delegate
,因为您在编译时并不知道实际的类型。它需要使用MakeGenericType
从Func<T>
创建适当的委托类型。
var concreteType = DiscoverTypeInRuntime();
var methodName = "SomeNameIKnowInAdvance";
var methodInfo = concreteType.GetMethodInfo(methodName);
var funcType = typeof(Func<>).MakeGenericType(concreteType);
var func = Delegate.CreateDelegate(funcType, methodInfo)
这将创建正确类型的委托,引用正确的方法......但编译时类型仍然只是Delegate
。