为什么在变量之后没有进行转换?

时间:2013-12-27 08:00:05

标签: c# java language-design

拥有animal(Elephant).UseTrunk()更合乎逻辑吗?这样,您就不必像((Elephant)animal).UseTrunk()

那样使用所有这些额外的parantheses来混乱您的代码

这是出于历史原因吗?它会干扰其他语法吗?或者我错过了其他什么?

我对C#语法和语言的干净和纯粹几乎都有一种宗教尊重,但是对于我来说,转换语法总是让人觉得有点像黑羊。

PS。我知道(动物像大象).UseTrunk(),但这不是问题:)除了理论上它是一种解决方法 - 打破了语言清洁和纯粹的想法。

8 个答案:

答案 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。我认为这是面向对象的基本思想。