是否可以创建一个以T作为运行时参数的Func?

时间:2016-03-14 09:42:13

标签: c# generics delegates func

是否可以创建具有通用Func作为运行时参数的T

我正在使用Func创建一些使用泛型的实例。我想做这样的事情:

var myFunc = new Func<IEnumerable<T>>(x => new List<T>());
IEnumerable<string> result = myFunc<string>();
IEnumerable<int> result2 = myFunc<int>();
IEnumerable<Bar> result3 = myFunc<Bar>();

但它显然无法编译,因为此时T未知。下面的代码将编译,但由于我需要强类型List<T>,因此它不适用于我的情况。

var func = new Func<IList>(() => new ArrayList());

如果Func无法使用,Expressiondelegates是否可以使用

有关背景信息,我可以说我将此作为工厂模式的一部分与Unity IoC一起使用。我建立在这个例子上:Unity auto-factory with params

修改 我意识到我的问题很难被问到。对不起。我试图通过不包括背景(目的)来使问题变得简单。重点是我使用Unity作为IoC并且有一个看起来像这样的工厂:

public interface ICollectionWrapperFactory
{
    ICollectionWrapper<T> CreateCollection<T>(IEnumerable<T> items);
}

public class CollectionWrapperFactory :ICollectionWrapperFactory
{
    private readonly IUnityContainer _container;

    public CollectionWrapperFactory(IUnityContainer container)
    {
        _container = container;
    }

    public ICollectionWrapper<T> CreateCollection<T>(IEnumerable<T> items)
    {
        ICollectionWrapper<T> collectionWrapper;
        if (items == null)
        {
            collectionWrapper = _container.Resolve<ICollectionWrapper<T>>(new ParameterOverride("items", new T[0]));
        }
        else
        {
            collectionWrapper = _container.Resolve<ICollectionWrapper<T>>(new ParameterOverride("items", items));
        }
        return collectionWrapper;
    }
}

正在使用IUnityContainer来解析实例。但是我想从实现中删除对IUnityContainer的依赖性,因为服务定位器反模式。相反,我想做这样的事情:

public class CollectionWrapperFactory :ICollectionWrapperFactory
{
    private readonly Func<IEnumerable<T>, ICollectionWrapper<T>> _createFunc;

    public CollectionWrapperFactory(Func<IEnumerable<T>, ICollectionWrapper<T>> createFunc)
    {
        _createFunc = createFunc;
    }

    public ICollectionWrapper<T> CreateCollection<T>(IEnumerable<T> items)
    {
        ICollectionWrapper<T> collectionWrapper;
        if (items == null)
        {
            collectionWrapper = _createFunc(new T[0]);
        }
        else
        {
            collectionWrapper = _createFunc(items);
        }
        return collectionWrapper;
    }
}

public class CollectionWrapper<TModel> : ICollectionWrapper<TModel>
{
    private IEnumerable<TModel> _items;

    public CollectionWrapper(IEnumerable<TModel> items)
    {
        _items = items;
        TotalCount = items.Count();
    }
    public int TotalCount { get; set; }

    public IEnumerable<TModel> Items
    {
        get { return _items; }
        set { _items = value; }
    }
}

在我的注册中:

   container.RegisterType<ICollectionWrapperFactory, CollectionWrapperFactory>(
        new ContainerControlledLifetimeManager(),
        new InjectionConstructor(
            new Func<IEnumerable<T>, ICollectionWrapper<T>>(
                items => container.Resolve<ICollectionWrapper<T>>(new ParameterOverride("items", items)))));

container.RegisterType(typeof(ICollectionWrapper<>), typeof(CollectionWrapper<>), new TransientLifetimeManager());

这样我将从实现中删除对IUnityContainer的依赖,从而删除服务定位器反模式(我猜?)。相反,我需要注入func来创建实例,但我不知道如何使用泛型参数注入func。

正是我想要的好例子,但是有了泛型:

Factory pattern without service locator

Unity auto-factory with params

2 个答案:

答案 0 :(得分:1)

您可以将其包装在方法中。

public static class MyFactories {
    public static Func<IEnumerable<T>> CreateListFactory<T>() {
        return () => new List<T>();
    }
}
// ... somewhere else
var myFunc = MyFactories.CreateListFactory<string>();
var result = myFunc(); // it will be List<string>

修改 如果要声明通用字段/属性,则必须在类中指定泛型参数。

public class CollectionWrapperFactory<T> : ICollectionWrapperFactory
{
    private readonly Func<IEnumerable<T>, ICollectionWrapper<T>> _createFunc;

    public CollectionWrapperFactory(Func<IEnumerable<T>, ICollectionWrapper<T>> createFunc)
    {
        _createFunc = createFunc;
    }

    public ICollectionWrapper<T> CreateCollection(IEnumerable<T> items)
    {
        ICollectionWrapper<T> collectionWrapper;
        if (items == null)
        {
            collectionWrapper = _createFunc(new T[0]);
        }
        else
        {
            collectionWrapper = _createFunc(items);
        }
        return collectionWrapper;
    }
}

答案 1 :(得分:0)

您可以使用简单的方法作为工厂。

Func<IEnumerable<T>> CreateFunc<T>() {
    return () => new List<T>();
}

// Usage
var func = CreateFunc<string>();
var list = func();