У меня есть два интерфейса, определяемые следующим образом:
public interface IFoo
{
...
}
Public interface IFooWrapper<T> where T : IFoo
{
T Foo {get;}
}
Я хочу, чтобы иметь возможность объявлять коллекцию IFooWrappers, но я не хочу указывать реализацию IFoo.
В идеале я хочу сделать что-то вроде:
IList<IFooWrapper<*>> myList;
Я не могу найти способ обойти это.
Что случилось с
IList<IFooWrapper<IFoo>> myList?
public interface IFoo
{
...
}
public interface IFooWrapper : IFoo
{
...
}
public interface IFooWrapper<T> : IFooWrapper
where T : IFoo
{
...
}
IList<IFooWrapper> myList;
Это способ сделать то, что вы хотите
То, что я собираюсь предложить, является излишним для большинства ситуаций, поскольку обычно вы можете создать интерфейс выше в иерархии, которую вы можете использовать. Однако я считаю, что это наиболее гибкое решение в некотором роде и наиболее точное представление о том, что вы хотите:
public interface IFooWrapperUser<U> {
U Use<T>(IFooWrapper<T> wrapper);
}
public interface IFooWrapperUser {
void Use<T>(IFooWrapper<T> wrapper);
}
public interface IExistsFooWrapper {
U Apply<U>(IFooWrapperUser<U> user);
void Apply(IFooWrapperUser user);
}
public class IExistsFooWrapper<T> : IExistsFooWrapper {
private IFooWrapper<T> wrapper;
public IExistsFoo(IFooWrapper<T> wrapper) {
this.wrapper = wrapper;
}
public U Apply<U>(IFooWrapperUser<U> user) {
return user.Use(foo);
}
public void Apply(IFooWrapperUser user) {
user.Use(foo)
}
}
Теперь вы можете создать экземпляр IList<IExistsFooWrapper>
, который можно использовать, как если бы он был IList<IFooWrapper<*>>
. Недостатком является создание класса для инкапсуляции логики, которую вы хотите запускать для каждого элемента:
private class FooPrinter : IFooWrapperUser<string> {
public string Apply<T>(IFooWrapper<T> wrapper) {
return wrapper.Foo.ToString();
}
}
...
IFooWrapperUser<string> user = new FooPrinter();
foreach (IExistFooWrapper wrapper in list) {
System.Console.WriteLine(wrapper.Apply(user));
}
...
public class FooWrapper : IFooWrapper<IFoo>