Warum kann ich 1 als Short übergeben, aber nicht die int-Variable i?

146

Warum funktioniert das erste und zweite Schreiben, aber nicht das letzte? Gibt es eine Möglichkeit, alle 3 zuzulassen und festzustellen, ob es 1, (int) 1 war oder ich übergeben habe? Und warum darf man nur den letzten? Das zweite erlaubt, aber nicht das letzte, hat mich wirklich umgehauen.

Demo zur Anzeige eines Kompilierungsfehlers

using System;
class Program
{
    public static void Write(short v) { }
    static void Main(string[] args)
    {
        Write(1);//ok
        Write((int)1);//ok
        int i=1;
        Write(i);//error!?
    }
}
CodesInChaos
quelle
2
Auch ich bin verblüfft, ich muss oft Ints zu kurz in Funktionsaufrufen werfen, obwohl sie besetzbar sein sollten ...
Mathieu Dumoulin
2
@ MathieuDumoulin sie sind gießbar, deshalb kannst du sie gießen. Aber es ist eine verlustbehaftete Konvertierung (es gibt viele Ints, die nicht in einen Kurzfilm passen), daher ist eine implizite Besetzung nicht möglich. Deshalb müssen Sie schreiben (short) i.
Abel

Antworten:

186

Die ersten beiden sind konstante Ausdrücke, der letzte nicht.

Die C # -Spezifikation ermöglicht eine implizite Konvertierung von int nach short für Konstanten, jedoch nicht für andere Ausdrücke. Dies ist eine vernünftige Regel, da der Compiler für Konstanten sicherstellen kann, dass der Wert in den Zieltyp passt, für normale Ausdrücke jedoch nicht.

Diese Regel steht im Einklang mit der Richtlinie, dass implizite Konvertierungen verlustfrei sein sollten.

6.1.8 Implizite Konvertierungen konstanter Ausdrücke

Eine implizite Konvertierung konstanter Ausdrücke ermöglicht die folgenden Konvertierungen:

  • Ein konstanter Ausdruck (§7.18) vom Typ intTyp umgewandelt werden kann sbyte, byte, short, ushort, uint, oder ulong, sofern der Wert des konstanten Ausdrucks innerhalb des Bereichs des Zieltypen.
  • Ein konstanter Ausdruck vom Typ longkann in Typ konvertiert werden ulong, vorausgesetzt, der Wert des konstanten Ausdrucks ist nicht negativ.

(Zitiert aus C # Language Specification Version 3.0)

CodesInChaos
quelle
67

Aufgrund der Möglichkeit der Kürzung erfolgt keine implizite Konvertierung von intnach short. Ein konstanter Ausdruck kann jedoch vom Compiler als vom Zieltyp behandelt werden .

1? Kein Problem: Es ist eindeutig ein gültiger shortWert. i? Nicht so sehr - es könnte zum Beispiel ein Wert sein short.MaxValue, und der Compiler kann dies im allgemeinen Fall nicht überprüfen.

Konrad Rudolph
quelle
Also ... es spielt keine Rolle, wie explizit ich bin ...> _ <. Haben Sie eine Idee, ob ich feststellen kann, ob ein Litereal oder eine int-Variable übergeben wurde?
@ acidzombie24 Das kannst du nicht. Aber warum willst du das tun?
Adam Houldsworth
@ acidzombie24 Ich glaube nicht, dass du das erkennen kannst. Sie können jedoch ein Vorlagenargument verwenden und dann mithilfe der Reflektion den Typ ermitteln.
Konrad Rudolph
3
@ acidzombie24 Es gibt keine Möglichkeit, ein Literal zur Laufzeit zu übergeben. Sie können also einfach Ihre Augen verwenden, um beim Kompilieren zu überprüfen.
Justin
1
@ acidzombie24 Wäre es in diesem Fall eine Option, das Argument als zu akzeptieren Expression<Func<int>>? Dann können Sie übergeben () => 1oder () => iinnerhalb der Funktion überprüfen, ob die übergebene Entität eine erfasste Variable oder einen konstanten Wert enthält.
Konrad Rudolph
8

Ein int Literal kann implizit in konvertiert werden short. Wohingegen:

Sie können nicht implizit nonliteral numerische Typen von größerer Speichergröße konvertieren kurzen

Die ersten beiden funktionieren also, weil die implizite Konvertierung von Literalen erlaubt ist.

Damien_The_Unbeliever
quelle
3
Ihre Antwort ist etwas falsch. Sie sollten keinen wörtlichen, sondern konstanten Ausdruck verwenden . Insbesondere ist das zweite Beispiel kein Literal .
CodesInChaos
6

Ich glaube, das liegt daran, dass Sie in den ersten beiden eine Literal / Konstante übergeben, aber es gibt keine automatische Typkonvertierung, wenn Sie in der dritten eine Ganzzahl übergeben.

Edit: Jemand hat mich geschlagen!

Justin
quelle
3

Weil es keine implizite Konvertierung zwischen nichtliteralem Typ und größerem Short gibt.

Eine implizite Konvertierung ist nur für konstante Ausdrücke möglich.

public static void Write(short v) { }

Wohin Sie integerWert als Argument übergebenshort

int i=1;
Write(i);  //Which is Nonliteral here
Vishal Suthar
quelle
3

Der Compiler hat gesagt , warum der Code fehlschlägt:

cannot convert `int' expression to type `short'

Hier ist die Frage, die Sie sich stellen sollten: Warum schlägt diese Konvertierung fehl? Ich googelte "c # convert int short" und landete auf der MS C # -Seite für das shortSchlüsselwort:

http://msdn.microsoft.com/en-us/library/ybs77ex4(v=vs.71).aspx

Wie auf dieser Seite angegeben, sind implizite Umwandlungen von einem größeren Datentyp shortnur für Literale zulässig. Der Compiler kann erkennen, wann ein Literal außerhalb des Bereichs liegt, aber nicht anders. Daher muss sichergestellt werden, dass Sie einen Fehler außerhalb des Bereichs in Ihrer Programmlogik vermieden haben. Diese Bestätigung wird von einer Besetzung gegeben.

Write((short)i)
Isaac Rabinovitch
quelle
0

Das Konvertieren von int -> short kann zum Abschneiden von Daten führen. Deshalb.

ak1238
quelle