拥有animal(Elephant).UseTrunk()
更合乎逻辑吗?这样,您就不必像((Elephant)animal).UseTrunk()
这是出于历史原因吗?它会干扰其他语法吗?或者我错过了其他什么?
我对C#语法和语言的干净和纯粹几乎都有一种宗教尊重,但是对于我来说,转换语法总是让人觉得有点像黑羊。
PS。我知道(动物像大象).UseTrunk(),但这不是问题:)除了理论上它是一种解决方法 - 打破了语言清洁和纯粹的想法。
答案 0 :(得分:3)
语法
((Elephant) animal).UseTrunk();
来自C,C ++。新的C#可能性 ,为。
如果Elephant
是类,而不是 struct 最精确的演员表,恕我直言,
Elephant elephant = animal as Elephant;
if (!Object.ReferenceEquals(null, elephant))
elephant.UseTrunk();
else {
// animal isn't an elephant - do nothing, throw exception etc.
}
但经常(如果您非常确定 animal
事实为Elephant
),您可以简单地提出
(animal as Elephant).UseTrunk(); // <- Not recommended, see Athari's comment
如果Elephant
是 struct ,那么在最准确的情况下,您必须执行类似
// Drawback: you have to cast twice
if (animal is Elephant) // <- 1st cast
((Elephant) animal).UseTrunk(); // <- 2nd cast
答案 1 :(得分:3)
((Elephant)animal).UseTrunk()
来自C ++,C#源自C ++。
C ++也有函数语法Elephant(animal).UseTrunk()
,但C#语言设计者决定不支持它。原因是它提供了很少的好处,同时使名称解析的逻辑复杂化。精心设计的程序不应该使用类型转换,所以这不是问题。
您可以使用以下扩展方法简化代码:
public static T To<T> (this object @this)
{
return (T)@this;
}
您的示例变为animal.To<Elephant>().UseTrunk()
,这与您建议的语法非常接近。
答案 2 :(得分:2)
正如其他人所指出的那样,这种前缀强制语法至少可以追溯到C语言,在很长一段时间之前就已经过了面向对象的编程。
如果它是一个后缀运算符,就像在你的例子中那样,解析器就很难将它与函数调用区分开来。前缀括号尚未使用。
它确实可以归结为“我们需要一种语法,这种方法很容易实现,并且不会让人感到非常难看。”
答案 3 :(得分:1)
有(animal as Elephant).UseTrunk()
,相同的顺序和相同数量的括号。但我还是喜欢常规演员。它来自C甚至更早,所以是的,历史原因。
答案 4 :(得分:1)
你建议的语法含糊不清!由于dot
是c#中的主要运算符,因此它具有最高优先级,因此如果不使用括号,您如何解析animal(Elephant).UseTrunk()
?正如您所说,UseTrunk()
应该应用于animal(Elephant)
而不是(Elephant)
,并且由于dot
具有更高的优先级,因此会产生某种歧义。但是如果你想降低dot
的优先级,那么作为一名语言设计师,你将面临更多的复杂问题。此外,使用这种语法,您将如何处理方法调用?您如何区分方法调用和强制转换操作符?所以实际上最好的方法是使用额外的括号来控制情况。
答案 5 :(得分:1)
我确实发现你的建议更简洁,它可以节省一些按键。但是当涉及到方法时,它可能会令人困惑。对最坏情况进行一些比较:
var i = (int)Get(); //existing syntax
var i = Get()(int); //what you propose
var i = (int)Get<int>(typeof(int)); //existing syntax
var i = Get<int>(typeof(int))(int); //what you propose
var i = ((Mammoth)(Elephant)Get()).Trunk; //existing syntax
var i = Get()(Elephant)(Mammoth).Trunk; //what you propose
var i = ((Mammoth)((Elephant)Get()).Trunk).Trunk; //existing syntax
var i = Get()(Elephant).Trunk(Mammoth).Trunk; //what you propose
到了每个人他自己到底。像python这样的语言有一种更具前瞻性的方法,例如:
i = int(animal);
但从技术上讲,这不是cast
运算符。
答案 6 :(得分:1)
拥有
animal(Elephant).UseTrunk()
是不合逻辑的。
C#已经使用了这种语法(和C一起使用)。这意味着,“调用函数animal
,传入Elephant
作为参数。然后在结果上调用UseTrunk()
。”
如果您还允许该语法作为类型强制,您必须找出一些方法来消除歧义。调整语法的一种方法是:
animal.(Elephant).UseTrack()
.(
使其明确无误,因为该语法当前没有用于任何事情。事实上,这正是Go类型强制的语法选择。
答案 7 :(得分:0)
因为不是每只动物都有useTrunk()
,但它应该是大象的特殊方法。假设每个动物都有walk()
,所以你可以使用animal()。walk(),但你不能调用animal()。useTrunk()除非你能确认这个类可以被强制转换(这个动物)绝对)elephant
。我认为这是面向对象的基本思想。