我是c#世界的新手,我正试图围绕仿制药.这是我目前的问题:
public Interface IAnimal{
string getType();
}
public Interface IAnimalGroomer<T> where T:IAnimal{
void groom(T);
}
Run Code Online (Sandbox Code Playgroud)
现在我想要一本包含这些动物美容师的字典.我怎么做?在java中,我可以这样做:
HashMap<String,IAnimalGroomer<?>> groomers = new HashMap<>();
Run Code Online (Sandbox Code Playgroud)
编辑:这是我正在尝试做的一个例子:
public class Dog : IAnimal
{
public string GetType()
{
return "DOG";
}
public void ClipNails() { }
}
public class DogGroomer : IAnimalGroomer<Dog>
{
public void Groom(Dog dog)
{
dog.ClipNails();
}
}
public class Program
{
private List<IAnimalGroomer<IAnimal>> groomers = new List<IAnimalGroomer<IAnimal>>();
public void doSomething()
{
//THIS DOESN"T COMPILE!!!!
groomers.Add(new DogGroomer());
}
}
Run Code Online (Sandbox Code Playgroud)
编辑 我认为我的意图在原帖中不明确.我的最终目标是制作一个使用不同类型的IAnimalGroomers的AnimalGroomerClinic.然后动物主人可以在诊所放下动物,诊所可以决定哪个美容师应该照顾动物:
public class AnimalGroomerClinic
{
public Dictionary<String, IAnimalGroomer> animalGroomers = new Dictionary<String,IAnimalGroomer>();
public void employGroomer(IAnimalGroomer groomer){
animalGroomers.add(groomer.getAnimalType(), groomer);
}
public void Groom(IAnimal animal){
animalGroomers[animal.getAnimalType()].Groom(animal);
}
}
Run Code Online (Sandbox Code Playgroud)
我意识到我可以在不使用泛型的情况下做到这一点.但是泛型允许我以IAnimalGroomer这样的方式编写接口:它(在编译时)绑定到特定的实例IAnimal.此外,具体类别IAnimalGroomer不需要一直投入IAnimals,因为泛型会迫使实现处理一种特定类型的动物.我以前在Java中使用过这个习惯用法,我只是想知道是否有类似的方法在C#中编写它.
编辑2: 很多有趣的讨论.我接受了一个答案,指出我在评论中动态调度.
Eri*_*ert 20
你想要的是调用站点协方差,这不是C#支持的功能.C#4及以上版本支持通用差异,但不支持呼叫站点差异.
但是,这对你没有帮助.你想要将狗美容师列入动物美容师列表中,但这在C#中无效.狗美容师不能用于需要动物美容师的任何环境中,因为狗美容师只能养狗,但动物美容师也可以训练猫.也就是说,当无法以协变方式安全使用时,您希望接口是协变的.
然而,您的IAnimalGroomer<T>界面可能是逆变的:动物美容师可以在需要狗美容师的环境中使用,因为动物美容师可以训练狗.如果你IAnimalGroomer<T>通过添加in声明来制作逆变,T那么你可以把它IAnimalGroomer<IAnimal>变成一个IList<IAnimalGroomer<Dog>>.
对于一个更现实的例子,认为IEnumerable<T>VS IComparer<T>.一系列狗可以用作动物序列; IEnumerable<T>是协变的.但是一系列动物可能不会被用作一系列的狗; 那里可能有一只老虎.
相比之下,比较动物的比较者可以用作狗的比较者; IComparer<T>是逆变.但是狗的比较可能不会被用来比较动物; 有人可以试着比较两只猫.
如果仍然不清楚,那么请阅读常见问题解答:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
然后回来问你有更多的问题.
有两个接口,IEnumerable并且IEnumerable<T>它们接近你试图完成什么.因此,可以有一本字典一样,你Dictionary<string,IEnumerable>可以包含任意值IEnumerable<int>,IEnumerable<string>等这里的窍门是派生IAnimalGroomer<T>从IAnimalGroomer,非通用接口.
编辑:
例如,根据您的请求,在创建一个名为的接口后IAnimalGroomer:
public interface IAnimalGroomer{
}
Run Code Online (Sandbox Code Playgroud)
,如果您更改以下行:
public interface IAnimalGroomer<T> where T:IAnimal{
Run Code Online (Sandbox Code Playgroud)
至
public interface IAnimalGroomer<T> : IAnimalGroomer where T:IAnimal{
Run Code Online (Sandbox Code Playgroud)
以及读取的行:
private List<IAnimalGroomer<IAnimal>> groomers = new List<IAnimalGroomer<IAnimal>>();
Run Code Online (Sandbox Code Playgroud)
至
private List<IAnimalGroomer> groomers=new List<IAnimalGroomer>();
Run Code Online (Sandbox Code Playgroud)
你的代码应该编译和工作.
正如布莱恩在上面的评论中指出的那样,也许dynamic是这里的出路。
查看以下代码。您可以获得泛型的好处,可以很好地绑定 API,并在您使用的底层dynamic使事情正常工作。
public interface IAnimal
{
}
public class Dog : IAnimal
{
}
public class Cat : IAnimal
{
}
public class BigBadWolf : IAnimal
{
}
//I changed `IAnimalGroomer` to an abstract class so you don't have to implement the `AnimalType` property all the time.
public abstract class AnimalGroomer<T> where T:IAnimal
{
public Type AnimalType { get { return typeof(T); } }
public abstract void Groom(T animal);
}
public class CatGroomer : AnimalGroomer<Cat>
{
public override void Groom(Cat animal)
{
Console.WriteLine("{0} groomed by {1}", animal.GetType(), this.GetType());
}
}
public class DogGroomer : AnimalGroomer<Dog>
{
public override void Groom(Dog animal)
{
Console.WriteLine("{0} groomed by {1}", animal.GetType(), this.GetType());
}
}
public class AnimalClinic
{
private Dictionary<Type, dynamic> groomers = new Dictionary<Type, dynamic>();
public void EmployGroomer<T>(AnimalGroomer<T> groomer) where T:IAnimal
{
groomers.Add(groomer.AnimalType, groomer);
}
public void Groom(IAnimal animal)
{
dynamic groomer;
groomers.TryGetValue(animal.GetType(), out groomer);
if (groomer != null)
groomer.Groom((dynamic)animal);
else
Console.WriteLine("Sorry, no groomer available for your {0}", animal.GetType());
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以这样做:
var animalClinic = new AnimalClinic();
animalClinic.EmployGroomer(new DogGroomer());
animalClinic.EmployGroomer(new CatGroomer());
animalClinic.Groom(new Dog());
animalClinic.Groom(new Cat());
animalClinic.Groom(new BigBadWolf());
Run Code Online (Sandbox Code Playgroud)
我不确定这是否是您所寻找的。希望能帮助到你!