Предоставление фабричный метод для ленивых когда существует еще один ленивый экземпляр фабрики?


Проблема

Я нашел себя нуждающихся экземпляр IObjectContext интерфейс, который никогда не должны быть null, но желая оттянуть экземпляра, пока некоторые необходимые ресурсы были загружены.

Я решил подойти к этому с ленивымно быстро столкнулся с проблемой-я также требуют IObjectSet что никогда не является нулем и ленивые экземпляры. Проблема заключается в следующем:

// 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<IObjectSet<TEntity>>(lazyContext.Value.FactoryMethodName);

Мое Решение

Хотелось бы предложения по улучшению на мой подход, или альтернативные подходы к проблеме.

public static class LazyExtensions {
    private class LazyFactory<T, TResult> where TResult : class {
        private readonly Lazy<T> _dependency;
        private readonly MethodInfo _factory;

        public LazyFactory(Lazy<T> 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<TOut> GetLazyFactory<TIn, TOut>(
        Lazy<TIn> dependency, MethodInfo factoryInfo) where TOut : class {
        return new LazyFactory<TIn, TOut>(dependency, factoryInfo).Invoke;
    }
}

Теперь я могу использовать GetLazyFactory() , чтобы написать следующее, и контекст не должен быть создан до lazyObjectSet.Стоимость доступа к:

var lazyFactory = LazyExtensions.GetLazyFactory<IObjectContext, IObjectSet<TEntity>>(
    new Lazy<IObjectContext>(factory.Create), 
    typeof (IObjectContext).GetMethod("ObjectSet"));

var lazyObjectSet = new Lazy<IObjectSet<TEntity>>(lazyFactory);

Как можно было бы улучшить, и есть ли лучший способ сделать это?



1273
4
задан 17 ноября 2011 в 04:11 Источник Поделиться
Комментарии
1 ответ

В сочетании с остальной частью кода, следующая строка показывает ошибку:

Contract.Requires(typeof(TResult).Equals(lazyFactory.ReturnType));

Проблема в том, что мой IObjectContext.ObjectSet() метод имеет универсальный тип возврата IObjectSetи lazyFactory нет тип информации для TEntity.

В частности, тип параметра для lazyFactory неизвестно, потому что его получают через GetMethod(). В результате, метод Equals() возвращает false и ограничение выдает исключение.

Я решил проблему путем изменения GetLazyFactory , чтобы принять имя метода строкой и получить объект methodinfo себя, называя MakeGenericMethod() по мере необходимости.

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;
}

1
ответ дан 6 декабря 2011 в 08:12 Источник Поделиться