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:
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;
}
}
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();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.