0

Is it possible to create a Func that has a generic T as runtime parameter?

I'm using Func to create some instances that are using generics. I would like to do something like this:

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>();

But it obviously doesn't compile because T is unknown at this moment. The code below will compile, but it will not work in my case since I need the strongly typed List<T>.

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

If it's not possible with Func, is it possible with Expression or delegates?

For background info I can say that I'm using this as part of a factory pattern together with Unity IoC. I'm building on this example: Unity auto-factory with params.

EDIT: I realise that my question was poorly asked. Sorry for that. I tried to keep the question simple by not including the background (purpose). The whole point is that I'm using Unity as IoC and have a factory that looks like this:

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

It is using the IUnityContainer to resolve the instance. But I want to remove the dependency to IUnityContainer from the implementation because of the service locator anti-pattern. Instead I want to do something like this:

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

And in my registration:

   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());

This way I will remove the dependency to IUnityContainer from the implementation and thus the service locator anti-pattern (I guess?). Instead I need to inject the func to create the instance, but I don't know how to inject a func with a generic parameter.

Good examples for exactly what I want, but with generics:

Factory pattern without service locator

Unity auto-factory with params

Community
  • 1
  • 1
smoksnes
  • 10,509
  • 4
  • 49
  • 74

2 Answers2

1

You can wrap that in method.

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>

EDIT: If you want declare generic fields/properties, you must specify the generic parameter in class.

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;
    }
}
TcKs
  • 25,849
  • 11
  • 66
  • 104
  • Thank you. I've updated my question with a little more information regarding the problem. Do you think that it's still possible to do it this way? I need to be able to inject the method. – smoksnes Mar 14 '16 at 10:10
  • I believe you're right. But I really wanted to avoid this since the factory is used on a lot of places and I would like to keep the class itself non-generic, but with generic methods. Thanks for clearing it out for me. – smoksnes Mar 14 '16 at 12:29
  • It's small class. The unity performance overhead is bigger than instantiation of this class. – TcKs Mar 14 '16 at 13:16
0

You can use a simple method as a factory.

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

// Usage
var func = CreateFunc<string>();
var list = func();
Maarten
  • 22,527
  • 3
  • 47
  • 68