Closed rizi closed 1 year ago
You can use a custom Instance
type for the parent, open type, then override the CloseType()
method to return a subtype of LambaInstance that then calls through to your factory.
So something like:
public class MyBuilderInstance<T> : LambdaInstance<IFoo<T>>
{
// and call through to the base constructor with s => BuildUsingFooFactory(typeof(T));
}
// and a custom instance like:
public class OpenFooInstance : Instance
{
// override the CloseType() method to return the right MyBuilderInstance<T> where T would be the single template type
// the service type should be typeof(IFoo<>)
}
Hi, Thx for the hint, I was able to create a "generic" solution that should work for any type (not only for IFoo
/IAsyncRetryPolicy<>) --> of course it's a first draft and I would like to get feedback if I can make things better.
If you like it I could also make a pull request so that this feature is available for everyone (if so I think we need better names for OpenBuilderFactory and OpenBuilderInstance ;) ).
Please see the sample below.
And I have another question when I derive from Instance I have to implement three methods
and I have no idea how this should be implemented correctly, atm I just throw an exception and it seems this methods get not called atm, is this the correct implementation or how should I implement these methods?
br
note: IFoo
IContainer container = new Container(configuration =>
{
configuration
.For(typeof(IAsyncRetryPolicy<>))
.Use(new OpenBuilderInstance(typeof(IAsyncRetryPolicy<>), ServiceLifetime.Transient,
(context, types) =>
{
Type closedTypeOfIPolicies = typeof(AsyncRetryPolicyProxy<>).MakeGenericType(types);
object asyncRetryPolicyFactory = context.GetRequiredService(closedTypeOfIPolicies);
return asyncRetryPolicyFactory;
}));
});
IAsyncRetryPolicy<string> asyncRetryPolicy = container.GetInstance<IAsyncRetryPolicy<string>>();
public class OpenBuilderFactory<TResult> : LambdaInstance<IServiceContext, TResult>
{
public OpenBuilderFactory(Type serviceType, Func<IServiceContext, Type[], object> creationFactory, ServiceLifetime lifetime)
: base(serviceType, c => (TResult)creationFactory(c, typeof(TResult).GenericTypeArguments), lifetime)
{
}
}
public class OpenBuilderInstance : Instance
{
private readonly Func<IServiceContext, Type[], object> _creationFactory;
public OpenBuilderInstance(Type type, ServiceLifetime lifetime, Func<IServiceContext, Type[], object> creationFactory)
: base(type, type, lifetime)
{
_creationFactory = creationFactory;
}
public override Instance CloseType(Type serviceType, Type[] templateTypes)
{
if (!ImplementationType.IsOpenGeneric())
throw new NotSupportedException($"{nameof(OpenBuilderInstance)} must be used with a generic type.");
Type builderInstance = typeof(OpenBuilderFactory<>).MakeGenericType(serviceType);
return (Instance)Activator.CreateInstance(builderInstance, serviceType, _creationFactory, Lifetime)!;
}
public override Func<Scope, object> ToResolver(Scope topScope)
{
throw new NotSupportedException();
}
public override object Resolve(Scope scope)
{
throw new NotSupportedException();
}
public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot)
{
throw new NotSupportedException();
} Type builderInstance = typeof(OpenBuilderFactory<>).MakeGenericType(serviceType);
return (Instance)Activator.CreateInstance(builderInstance, serviceType, _factory, Lifetime)!;
}
public override Func<Scope, object> ToResolver(Scope topScope)
{
throw new NotImplementedException();
}
public override object Resolve(Scope scope)
{
throw new NotSupportedException();
}
public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot)
{
throw new NotSupportedException();
}
public override Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot)
{
throw new NotSupportedException();
}
}
@jeremydmiller I have another question when I derive from Instance I have to implement three methods
Variable CreateVariable(BuildMode mode, ResolverVariables variables, bool isRoot) object Resolve(Scope scope) Func<Scope, object> ToResolver(Scope topScope))
I have no idea how this should be implemented correctly, atm I just throw an exception and it seems this methods get not called atm, is this the correct implementation or how should I implement these methods?
Br
@jeremydmiller are you interested in a PR? If yes, please let me know and please answer my questions above?
If no, I will close the issue.
Br
@rizi Sorry for being slow here, yes, just throw new NotSupportedException() in those methods. If I get around to it, I can finally formalize this pattern a bit. It comes up a couple times a year.
No activity, closing.
Hi, I know it's not the best solution, but we have exactly that use case:
Is there a way to get the information of the current requested type, like it was possible with StructureMap?
This question is quite similar, but unfortunately it has no answer: https://stackoverflow.com/questions/68832353/how-can-i-get-the-requested-type-in-a-usectx-factory-func-in-lamar-5 Br