好。所以我目前正在尝试在C#中创建一个接口列表,该接口将接口作为参数。为了使这个更清楚,让我举一个例子:
public interface IPlate<T> where T : IWaffle {}
public interface IWaffles {}
public class BelgiumWaffle : IWaffle {}
public class FalafelWaffle : IWaffle {}
public class HugePlate : IPlate<BelgiumWaffle> {}
public class SmallPlate : IPlate<FalafelWaffle> {}
// Now, I want to do the following:
var plates = new List<IPlate<IWaffle>>();
plates.add(new HugePlate());
plates.add(new SmallPlate());
目标是能够将IPlate对象列表序列化为XML。我希望使用泛型来做到这一点,但我一直在收到错误告诉我在尝试添加时存在一些参数错误(也就是说 - 类型不匹配)。只是不确定我在这里做错了什么。对我来说似乎是对的,但我必须遗漏一些东西(显然)。
更新:我应该提一下,这是.NET v3.5
更新:抱歉!在写关于板类定义的问题时有一些错别字。
答案 0 :(得分:4)
我认为你应该使用协方差(.NET 4.0)
public interface IPlate<out T> where T : IWaffle {}
并将IPancake
替换为IWaffle
var plates = new List<IPlate<IPancake>>();
答案 1 :(得分:2)
HugePlate
和SmallPlate
都不会实现IPlate<IPancake>
列表所需的plates
接口。
答案 2 :(得分:1)
除了协方差(正如@JakubKonecki已经指出的那样),你对HugePlate和SmallPlate的定义看起来不正确,因为他们需要实现IPlate
。
试试这个:
public interface IPlate<out T> where T : IWaffle {}
public interface IWaffle {}
public class BelgiumWaffle : IWaffle {}
public class FalafelWaffle : IWaffle {}
public class HugePlate<T> : IPlate<T> where T : IWaffle {}
public class SmallPlate<T> : IPlate<T> where T : IWaffle {}
答案 3 :(得分:1)
在.NET Framework 3.5中,您没有 out
参数用于泛型协方差,就像在.NET Framework 4.0中一样。
您可以尝试使用IPlate
的非通用版本来解决此问题(在这种情况下,我将其命名为IPlateNG
)。
请考虑 .NET Framework 4.0 中的以下示例(我必须展开它以显示我的观点):
using System;
using System.Collections.Generic;
public interface IWaffle { string Eat(); }
// on C# 4.0 you just put the "out" to mark the covariance (and that is it)
public interface IPlate<out T> where T : IWaffle { T GetMyWaffle(); }
public class BelgiumWaffle : IWaffle {
public string Eat() { return "Eating a Belgium Waffle"; }
public string Breakfast() { return "Breakfasting a Belgium Waffle"; }
}
public class FalafelWaffle : IWaffle {
public string Eat() { return "Eating a Falafel Waffle"; }
public string Dinner() { return "Having dinner with a Falafel Waffle"; }
}
public class HugePlate : IPlate<BelgiumWaffle> {
public BelgiumWaffle GetMyWaffle() { return new BelgiumWaffle(); }
}
public class SmallPlate : IPlate<FalafelWaffle> {
public FalafelWaffle GetMyWaffle() { return new FalafelWaffle(); }
}
class Program
{
static void Main(string[] args)
{
var plates = new List<IPlate<IWaffle>>();
plates.Add(new HugePlate());
plates.Add(new SmallPlate());
IPlate<IWaffle> aPlate = plates[0];
// Anyway, when you get a member of the collection you'll get the interface, not a concrete class (obviously).
IWaffle aWaffle = aPlate.GetMyWaffle();
// So you cannot invoke any specifics (like Breakfast or Dinner)
Console.WriteLine(aWaffle.Eat());
// But if you cast the member of the collection to the specific class (or interface)
IPlate<FalafelWaffle> aSmallPlate = (SmallPlate)plates[1];
// Then you'll get the concrete class without casting again
FalafelWaffle aFalafel = aSmallPlate.GetMyWaffle();
Console.WriteLine(aFalafel.Dinner());
}
}
现在,对于 .NET Framework 3.5 :
,这将是相同的using System;
using System.Collections.Generic;
public interface IWaffle { string Eat(); }
// In this case I define this extra inteface which is non-generic
// And inside it, we need a new method equivalent to the one on the generic one
public interface IPlateNG { IWaffle GetWaffle(); }
// And make the generic one implement the non-generic one
public interface IPlate<T> : IPlateNG where T : IWaffle { T GetMyWaffle(); }
public class BelgiumWaffle : IWaffle {
public string Eat() { return "Eating a Belgium Waffle"; }
public string Breakfast() { return "Breakfasting a Belgium Waffle"; }
}
public class FalafelWaffle : IWaffle {
public string Eat() { return "Eating a Falafel Waffle"; }
public string Dinner() { return "Having dinner with a Falafel Waffle"; }
}
public class HugePlate : IPlate<BelgiumWaffle> {
// This extra method is needed due the lack of the 'out' on the definition
public IWaffle GetWaffle() { return GetMyWaffle(); }
public BelgiumWaffle GetMyWaffle() { return new BelgiumWaffle(); }
}
public class SmallPlate : IPlate<FalafelWaffle> {
// This extra method is needed due the lack of the 'out' on the definition
public IWaffle GetWaffle() { return GetMyWaffle(); }
public FalafelWaffle GetMyWaffle() { return new FalafelWaffle(); }
}
class Program
{
static void Main(string[] args)
{
// The list cannot work with the IPlate<IWaffle> anymore. So here comes IPlateNG to the rescue
var plates = new List<IPlateNG>();
plates.Add(new HugePlate());
plates.Add(new SmallPlate());
IPlateNG aPlate = plates[0];
// And instead of calling to the GetMyWaffle method we can call to the GetWaffle in this case
IWaffle aWaffle = aPlate.GetWaffle();
Console.WriteLine(aWaffle.Eat());
IPlate<FalafelWaffle> aSmallPlate = (SmallPlate)plates[1];
FalafelWaffle aFalafel = aSmallPlate.GetMyWaffle();
Console.WriteLine(aFalafel.Dinner());
}
}
请注意,我必须在GetMyWaffle
个具体类上创建GetWaffle
(名为IPlate
)的额外非泛型版本,以解决“ out”缺少的问题“关键字。但其余的非常相似。
答案 4 :(得分:0)
在3.5中工作,感谢@JakubKonecki指出协方差
public interface IWaffle { }
public interface IPlate<out T> where T : IWaffle { }
public interface IPancake : IWaffle { }
public class BelgiumWaffle : IWaffle {}
public class FalafelWaffle : IWaffle {}
public class HugePlate : IPlate<BelgiumWaffle> {}
public class SmallPlate : IPlate<FalafelWaffle> { }
var plates = new List<IPlate<IWaffle>>();
plates.Add(new HugePlate());
plates.Add(new SmallPlate());
答案 5 :(得分:0)
你可以使用抽象类而不是T的接口吗?
public abstract class Waffle { }
public interface IPlate<T> where T : Waffle
{
T Food
{
get;
set;
}
}
public class BelgiumWaffle : Waffle { }
public class FalafelWaffle : Waffle { }
public class HugePlate<T> : IPlate<T> where T : Waffle
{
public HugePlate(T food)
{
this.Food = food;
}
public T Food
{
get;
set;
}
}
public class SmallPlate<T> : IPlate<T> where T : Waffle
{
public SmallPlate(T food)
{
this.Food = food;
}
public T Food
{
get;
set;
}
}
public class Test
{
Test()
{
var platesOfWaffle = new List<IPlate<Waffle>>();
platesOfWaffle.Add(new HugePlate<Waffle>(new BelgiumWaffle()));
platesOfWaffle.Add(new SmallPlate<Waffle>(new FalafelWaffle()));
}
}