[英]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.