patterncsharpMinor
Providing factory method to Lazy<T> when factory exists on another lazy instance?
Viewed 0 times
methodfactoryexistsprovidinginstancelazyanotherwhen
Problem
The Problem
I found myself needing an instance of an
I decided to approach this with
My Solution
I would like suggestions for improvements on my approach, or alternative approaches to the problem.
Now I can use
How can t
I found myself needing an instance of an
IObjectContext interface that should never be null, but wanting to delay instantiation until after some required resources have been loaded.I decided to approach this with
Lazy, but quickly ran into an issue -- I also require an IObjectSet that is never null and lazy instantiated. The problem is this:// lazyObjectSet needs to be created directly after lazyContext, but I need to
// delay instantiating both. The desired factory method exists on lazyContext,
// but accessing lazyContext.Value instantiates context before it is needed:
//
var lazyObjectSet = new Lazy>(lazyContext.Value.FactoryMethodName);My Solution
I would like suggestions for improvements on my approach, or alternative approaches to the problem.
public static class LazyExtensions {
private class LazyFactory where TResult : class {
private readonly Lazy _dependency;
private readonly MethodInfo _factory;
public LazyFactory(Lazy lazyDependency, MethodInfo lazyFactory) {
// Argument null checks omitted for brevity
Contract.Requires(typeof(TResult).Equals(lazyFactory.ReturnType));
Contract.Requires(lazyFactory.GetParameters().Count() == 0);
_factory = lazyFactory;
_dependency = lazyDependency;
}
public TResult Invoke() {
return (TResult) _factory.Invoke(_dependency.Value, null);
}
}
public static Func GetLazyFactory(
Lazy dependency, MethodInfo factoryInfo) where TOut : class {
return new LazyFactory(dependency, factoryInfo).Invoke;
}
}Now I can use
GetLazyFactory() to write the following, and the context should not be instantiated until lazyObjectSet.Value is accessed:var lazyFactory = LazyExtensions.GetLazyFactory>(
new Lazy(factory.Create),
typeof (IObjectContext).GetMethod("ObjectSet"));
var lazyObjectSet = new Lazy>(lazyFactory);How can t
Solution
In conjunction with the rest of the code, the following line exhibits a bug:
The problem is that my
Specifically, the type parameter for
I solved the problem by modifying
Contract.Requires(typeof(TResult).Equals(lazyFactory.ReturnType));The problem is that my
IObjectContext.ObjectSet() method has the generic return type IObjectSet, and lazyFactory doesn't have type information for TEntity.Specifically, the type parameter for
lazyFactory is unknown because it's obtained using GetMethod(). As a result, Equals() returns false and the constraint fails with an exception. I solved the problem by modifying
GetLazyFactory to accept a method name string and obtain the MethodInfo itself, calling MakeGenericMethod() as necessary.public static Func GetLazyFactory(Lazy dependency, string factoryName)
where TOut : class
{
Type outT = typeof(TOut); // Expected return type of factory method
MethodInfo factoryMethodInfo = // Should return TOut
typeof(TIn).GetMethod(factoryName);
if(outT.IsGenericType)
{
// Get generic type argument of TOut, making sure exactly 1 exists.
Type tParam = outT.GetSingleGenericArgument();
// We must specify the generic type or Type.Equals() will yield false.
factoryMethodInfo = factoryMethodInfo.MakeGenericMethod(tParam);
}
return new LazyFactory(dependency, factoryMethodInfo).Invoke;
}Code Snippets
Contract.Requires(typeof(TResult).Equals(lazyFactory.ReturnType));public static Func<TOut> GetLazyFactory<TIn, TOut>(Lazy<TIn> dependency, string factoryName)
where TOut : class
{
Type outT = typeof(TOut); // Expected return type of factory method
MethodInfo factoryMethodInfo = // Should return TOut
typeof(TIn).GetMethod(factoryName);
if(outT.IsGenericType)
{
// Get generic type argument of TOut, making sure exactly 1 exists.
Type tParam = outT.GetSingleGenericArgument();
// We must specify the generic type or Type.Equals() will yield false.
factoryMethodInfo = factoryMethodInfo.MakeGenericMethod(tParam);
}
return new LazyFactory<TIn, TOut>(dependency, factoryMethodInfo).Invoke;
}Context
StackExchange Code Review Q#6124, answer score: 2
Revisions (0)
No revisions yet.