[英]C# Function return instance of type Interface with Generic Types
我有以下内容:
public interface IInput
{
}
public interface IOutput
{
}
public interface IProvider<Tin, Tout>
where Tin : IInput
where Tout : IOutput
{
}
public class Input : IInput
{
}
public class Output : IOutput
{
}
public class Provider : IProvider<Input, Output>
{
}
我希望能够获得以下方法来转换结果:
private static IProvider<IInput, IOutput> GetProvider()
{
return new Provider();
}
我知道类型不同,但是它们实现了接口。
有什么线索吗?
使它起作用的唯一方法是IProvider
的通用属性是否协变。
public interface IProvider<out Tin, out Tout>
where Tin : IInput
where Tout : IOutput
{
}
这样做可以消除示例代码的编译器错误,但是由于您没有在IProvider
显示对Tin
和Tout
因此无法确定它是否会给您带来其他编译器错误。
必须将其声明为协变变量才能将其用作参数的原因是,如果没有,则可能会导致不良后果。 这是一个简化的示例,说明它可能会出错:
public interface IAnimal { }
public class Dog : IAnimal { }
public class Cat : IAnimal { }
public interface IAnimalCollection<TAnimal> where TAnimal : IAnimal
{
TAnimal GetAnimal(int i);
int AddAnimal(TAnimal animal);
}
public class DogCollection : IAnimalCollection<Dog>
{
private List<Dog> _dogs = new List<Dog>();
public Dog GetAnimal(int i)
{
return _dogs[i];
}
public int AddAnimal(Dog animal)
{
_dogs.Add(animal);
return _dogs.Count - 1;
}
}
class Program
{
static void Main(string[] args)
{
IAnimalCollection<IAnimal> animalCollection = GetDogCollection();
animalCollection.AddAnimal(new Cat()); //We just added a cat to a collection of dogs.
}
private static IAnimalCollection<IAnimal> GetDogCollection()
{
return new DogCollection();
}
}
如果允许我们将DogCollection
作为IAnimalCollection<IAnimal>
,从而由于其为IAnimal
和AddAnimal
而使添加Cat
完全合法,则它将为int AddAnimal(IAnimal)
。
通过增加out
这使得AddAnimal
方法是非法的,但现在它是完全安全的,说:“狗的集合被表示为动物的集合”,因为现在还没有办法添加到集合中的动物不是狗。
要编译以上代码,您必须权衡两个因素之一。 使GetDogCollection()
不返回接口,并删除添加的cat。
class Program
{
static void Main(string[] args)
{
IAnimalCollection<IAnimal> animalCollection = GetDogCollection();
//animalCollection.AddAnimal(new Cat()); //Would get a compiler error if we tried to add a cat to the collection
}
private static IAnimalCollection<Dog> GetDogCollection()
{
return new DogCollection();
}
}
或使接口协变,但是要做到这一点,您需要从接口中删除AddAnimal
方法,这也不允许您将猫添加到集合中。
public interface IAnimalCollection<out TAnimal> where TAnimal : IAnimal
{
TAnimal GetAnimal(int i);
//int AddAnimal(TAnimal animal); //Can't have methods that take in the type when using "out"
}
class Program
{
static void Main(string[] args)
{
IAnimalCollection<IAnimal> animalCollection = GetDogCollection();
//animalCollection.AddAnimal(new Cat()); //Would get a compiler error because this method no longer exists.
}
private static IAnimalCollection<IAnimal> GetDogCollection()
{
return new DogCollection();
}
}
我冒着为您解释替代方法的风险。
也许我误会了。 似乎您正在寻找使用工厂方法创建提供程序实例的方法。
如果您采用这种方式,则无法避免在此处进行显式转换:
private static IProvider<IInput, IOutput> GetProvider()
{
// Explicit upcast
return (IProvider<IInput, IOuput>)new Provider();
}
一些建议:通用参数的通用命名方案是大写T
和小写的标识符,如TOutput
。
由于C#编译器知道TOutput
必须实现IOutput
,而TInput
必须实现IInput
这要归功于泛型约束,即使Provider
提供的泛型参数可以完全满足整个约束, 问题仍然出在工厂方法不能解决的时候隐式证明Provider
类的通用参数TOutput
/ TInput
与Provider
给工厂方法本身的参数相同 :
public static IProvider<TInput, TOutput> GetProvider<TInput, TOutput>()
where TInput : IInput
where TOutput : IOutput
{
// Hey!!!!!!!! Do TOutput and TInput of this method are the same as
// Provider TOutput and TInput? Who knows, thus, compiler error:
// Cannot implicitly convert type 'Provider' to 'IProvider<TInput,TOutput>'.
// An explicit conversion exists (are you missing a cast?)
return new Provider();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.