有一個外部泛型方法,我用反射呼叫它。但是有一個技巧:這個方法有一個如下的簽名—— Foo<TResult>(Func<Bar, TResult> factory). 問題是,在我的方法中,我TResult在運行時得到的不是泛型型別,而是動態的。實際上,我的方法有一個完整的目的——動態。我嘗試使用以下代碼作為反射的引數Foo:
Func<Bar, dynamic> factory = (bar) =>
{
return tResultInstance;
};
是的,我其實不需要Bar,這不是一個錯誤。:) 問題是當我呼叫我的反射Foo時,它會因轉換例外而失敗,因為它不能System.Object轉換為TResult.
那么,是否可以動態(在運行時)創建這樣的 Func 以將其傳遞給動態呼叫?
UPD 0。
靜止的。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<Baz>(_ => new Baz("string"));
動態的。
private const string AddScopedMethodName = "AddScoped";
private const string AddScopedMethodSignature = "Microsoft.Extensions.DependencyInjection.IServiceCollection AddScoped[TService](Microsoft.Extensions.DependencyInjection.IServiceCollection, System.Func`2[System.IServiceProvider,TService])";
<...>
var bazConstructorInfo = bazType.GetConstructor(new Type[1] // bazType is Baz.
{
typeof(String)
});
var bazConstructorParameters = new object[1]
{
inputString // inputString is "string".
};
var bazInstance = bazConstructorInfo.Invoke(bazConstructorParameters);
var addScopedMethodInfo = typeof(ServiceCollectionServiceExtensions)
.GetMethods()
.Where(method =>
method.IsPublic &&
method.IsGenericMethod &&
(method.Name == AddScopedMethodName) &&
(method.ToString() == AddScopedMethodSignature))
.Single();
var addScopedMethod = addScopedMethodInfo.MakeGenericMethod(bazType);
Func<IServiceProvider, dynamic> implementationFactory = (serviceProvider) =>
{
return bazInstance;
};
var addScopedMethodParameters = new object[2]
{
services, // services is IServiceCollection.
implementationFactory
};
addScopedMethod.Invoke(
services,
addScopedMethodParameters); // Fails with "Object of type 'System.Func`2[System.IServiceProvider,System.Object]' cannot be converted to type 'System.Func`2[System.IServiceProvider,Baz]'." exception. :(
UPD 1。
致@alexei-levenkov。看起來通用 Func<T> 的運行時創建不是對我的回答。他們正在使用以下代碼:
static Foo CreateFoo() { return new Foo(); }
<...>
var method = typeof(Program)
.GetMethod(
"CreateFoo",
BindingFlags.NonPublic | BindingFlags.Static);
Foo但就我而言,在運行之前我不知道。我就是寫不出這一static Foo CreateFoo() { return new Foo(); }行。
uj5u.com熱心網友回復:
一個快速的解決方法是添加輔助類:
class Helper
{
public static Func<IServiceProvider, T> GetFactory<T>(T instance) => _ => instance;
}
并使用它來獲取實作工廠:
var methodInfo = typeof(Helper).GetMethod(nameof(Helper.GetFactory));
var implementationFactory = methodInfo.MakeGenericMethod(bazType).Invoke(null, new[] { bazInstance });
但總的來說,當您可以直接使用時,所有這些似乎都是大材小用ServiceDescriptor:
Func<IServiceProvider, object> implementationFactory = _ => bazInstance;
var serviceDescriptor = new ServiceDescriptor(bazType, implementationFactory, ServiceLifetime.Scoped);
services.Add(serviceDescriptor);
實體創建反射也可以簡化為Activator.CreateInstance呼叫:
var services = new ServiceCollection();
Type bazType = typeof(Baz);
var bazConstructorParameters = new object[]
{
"string" // inputString is "string".
};
var bazInstance = Activator.CreateInstance(bazType, bazConstructorParameters);
Func<IServiceProvider, object> implementationFactory = _ => bazInstance;
var serviceDescriptor = new ServiceDescriptor(bazType, implementationFactory, ServiceLifetime.Scoped);
services.Add(serviceDescriptor);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/487094.html
下一篇:清潔架構-DTO場所
