首先,请记住.NET String是IConvertible和ICloneable.
现在,考虑以下非常简单的代码:
//contravariance "in"
interface ICanEat<in T> where T : class
{
void Eat(T food);
}
class HungryWolf : ICanEat<ICloneable>, ICanEat<IConvertible>
{
public void Eat(IConvertible convertibleFood)
{
Console.WriteLine("This wolf ate your CONVERTIBLE object!");
}
public void Eat(ICloneable cloneableFood)
{
Console.WriteLine("This wolf ate your CLONEABLE object!");
}
}
Run Code Online (Sandbox Code Playgroud)
然后尝试以下(在某些方法中):
ICanEat<string> wolf = new HungryWolf();
wolf.Eat("sheep");
Run Code Online (Sandbox Code Playgroud)
当编译它时,没有编译器错误或警告.运行它时,看起来调用的方法取决于我的class声明中的接口列表的顺序HungryWolf.(尝试在逗号(,)分隔列表中交换两个接口.)
问题很简单:这不应该给出编译时警告(或者在运行时抛出)吗?
我可能不是第一个提出像这样的代码的人.我使用了界面的逆变,但你可以用界面的covarainace做一个完全类似的例子.事实上,Lippert先生很久以前就做过这样的事情.在他博客的评论中,几乎每个人都认为这应该是一个错误.然而他们默默地允许这样做. …
在以下代码中:
interface IGet { int Value { get; } }
interface ISet { int Value { set; } }
interface IBoth : IGet, ISet { }
class Test
{
public void Bla(IBoth a)
{
var x = a.Value; // Error: Ambiguity between 'IGet.Value' and 'ISet.Value'
}
}
Run Code Online (Sandbox Code Playgroud)
我收到一个错误:
'IGet.Value'和'ISet.Value'之间的歧义
为什么编译器无法确定访问的属性必须来自IGet?
编辑 - 我猜测编译器首先尝试确定正在访问哪个属性,然后才检查它是get还是set.问题是 - 为什么?为什么不排除那些不提供吸气剂的候选人呢?为什么不解析实际的get/set方法并忽略它是属性的事实?
更新:使用方法而不是属性的更多代码,其中问题不存在.属性并不完全像一对方法.
我正在为游戏设计一个非常简单的库存系统.我遇到了一个障碍,我有一个需要接受多种类型对象的库存(一个特定类型的数组).我的代码:
IWeapon[] inventory = new IWeapon[5];
public void initialiseInventory(IWeapon weapon, IArmour armour)
{
inventory[0] = weapon; // Index 0 always contains the equipped weapon
inventory[1] = armour; // Index 1 always contains the equipped armour
}
Run Code Online (Sandbox Code Playgroud)
我会得到一个错误,指出数组不能将装甲对象转换为武器对象(这是数组类型).然后我想我可以创建IWeapon和IArmour将继承的超类(嗯,界面准确).但后来又遇到了另一个错误......
IItem[] inventory = new IItem[5];
public void initialiseInventory(IWeapon weapon, IArmour armour)
{
inventory[0] = weapon; // Index 0 always contains the equipped weapon
inventory[1] = armour; // Index 1 always contains the equipped armour
Console.WriteLine("The weapon name is: " + inventory[0].Name) // Problem! …Run Code Online (Sandbox Code Playgroud) 我最近发现臭名昭着的Jon Skeet关于使用LINQ to XML的帖子.这段特殊代码引起了我的注意:
// Customers is a List<Customer>
XElement customersElement = new XElement("customers",
customers.Select(c => new XElement("customer", //This line is "magic"
new XAttribute("name", c.Name),
new XAttribute("lastSeen", c.LastOrder)
new XElement("address",
new XAttribute("town", c.Town),
new XAttribute("firstline", c.Address1),
// etc
));
Run Code Online (Sandbox Code Playgroud)
我决定在我的应用程序中自己测试它,我有一个foreach循环设置如下:
foreach (var kvp in m_jobs) { //m_jobs is a Dictionary<string,Job>
m_xmlDoc.Root.Element("SCHED_TABLE").Add(
kvp.Value.GenerateXmlNode())
);
}
Run Code Online (Sandbox Code Playgroud)
我修改为:
m_xmlDoc.Root.Element("SCHED_TABLE").Add(
m_jobs.Select(job => job.Value.GenerateXmlNode())
};
Run Code Online (Sandbox Code Playgroud)
其中GenerateXmlNode()是为特定作业项生成适当XML标记的方法.我不确定会发生什么,但是它看起来和我的foreach循环完全一样.我不太明白的是为什么?!此外,这被认为是LINQ的"滥用"还是"功能"?
为清晰起见编辑:我知道.Select将返回一个IEnumerable,其中包含我要求的内容,但我并没有明确地枚举它.我理解.Add是如何工作的,因为它接受了可变数量的参数,但同样,我没有明确枚举传递这些参数.那么......它怎么还能用呢?
我有两个事件类,叫他们StatusChanged和ValueChanged.我想知道将这些'流'暴露为IObservable.正在实施IObservable<Status>并IObservable<Value>在同一个班级'坏'?是否可能导致我(或我班级的用户)悲伤?