2008-12-04 14 views

Antwort

49

ERROR: Eine Eigenschaft oder Indexer kann als aus nicht oder ref Parameter

Wenn Sie nicht angeben {get; set;} dann der Compiler weiß nicht weitergegeben werden, wenn es sich um ein Feld oder eine Eigenschaft ist. Dies ist wichtig, weil sie, während sie identisch aussehen, vom Compiler unterschiedlich behandelt werden. z.B. Der Aufruf von "InitAnInt" für die Eigenschaft führt zu einem Fehler.

class Test 
{ 
    public int n; 
    public int i { get; set; } 
    public void InitAnInt(out int p) 
    { 
     p = 100; 
    } 
    public Test() 
    { 
     InitAnInt(out n); // This is OK 
     InitAnInt(out i); // ERROR: A property or indexer may not be passed 
          // as an out or ref parameter 
    } 
} 

Sie nicht schaffen sollten öffentliche Felder/Variablen auf Klassen, man kann nie wissen, wenn Sie es haben & Satz Accessoren ändern werden wollen bekommen, und dann wissen Sie nicht, was Code du gehst vor allem, wenn Sie Clients haben, die gegen Ihre API programmieren.

Sie können auch verschiedene Zugriffsmodifikatoren für die get & setzen, z. {bekommen; private set;} macht das public und das set private zur deklarierenden Klasse.

62

Weil Sie vielleicht eine schreibgeschützte Eigenschaft wollen:

public int Foo { get; private set; } 

oder schreibgeschützte Eigenschaft:

public int Foo { private get; set; } 
+3

Sie können auch alle Arten von Modifikatoren hinzufügen, wie geschützt etc. – Tigraine

+0

Ja, und was andere Leute sagten ... Sie brauchen eine Möglichkeit, zwischen einem Feld und einer Eigenschaft zu unterscheiden. –

+1

Eine kleine Randnotiz: Es gibt das Konzept der Readonly-Felder. Das Framework wird sicherstellen, dass diese nur einmal geschrieben werden. Es unterscheidet sich von privaten Setter oder Getter, die geschrieben werden können, wenn Sie Zugriff haben. –

4

Der Compiler muss wissen, wenn Sie es wollen einen Getter zu erzeugen und/oder ein Setter oder vielleicht ein Feld deklarieren.

16

Weil Sie einen Weg brauchen, um es von normalen Feldern zu unterscheiden.

Es ist auch nützlich, verschiedene Zugriffsmodifizierer zu haben, z.

public int MyProperty { get; private set; } 
+0

Aber öffentliche Felder sind nutzlos. –

+0

Einverstanden. Die Syntax kann wahrscheinlich teilweise darauf zurückgeführt werden, dass mr anders kein neues Keyword in der Sprache einführen möchte. –

+1

Earwicker: Ich fand öffentliche Felder in meiner Vector2f-Klasse nützlich - sie haben das Programm viel beschleunigt (im Vergleich zu Eigenschaften), und die Klasse ist einfach genug, dass ich nie die Implementierung ändern muss. –

2

Wenn die Eigenschaft keine Accessoren hatte, wie würde der Compiler sie von einem Feld trennen? Und was würde es von einem Feld trennen?

16

Ich dachte nur, ich würde meine Erkenntnisse zu diesem Thema teilen.

Codierung einer Eigenschaft wie folgt ist eine .net 3.0-Verknüpfung Aufruf "automatisch implementierte Eigenschaft".

public int MyProperty { get; set; } 

Dies erspart Ihnen ein wenig Tipparbeit. Der lange Weg, um eine Immobilie zu erklären, ist wie folgt:

private int myProperty; 
public int MyProperty 
{ 
    get { return myProperty; } 
    set { myProperty = value; } 
} 

Wenn Sie die „Auto-implementierten Eigenschaft“ verwenden der Compiler den Code generiert, die get verkabeln und auf einige „k_BackingField“. Unten ist der demontierte Code mit Reflektor.

public int MyProperty 
{ 
    [CompilerGenerated] 
    get 
    { 
     return this.<MyProperty>k__BackingField; 
    } 
    [CompilerGenerated] 
    set 
    { 
     this.<MyProperty>k__BackingField = value; 
    } 
} 

zerlegten C# Code von IL

Auch Drähte ein Verfahren zur setter und Getter auf.

[CompilerGenerated] 
public void set_MyProperty(int value) 
{ 
    this.<MyProperty>k__BackingField = value; 
} 
[CompilerGenerated] 
public int get_MyProperty() 
{ 
    return this.<MyProperty>k__BackingField; 
} 

zerlegt C# -Code von IL

Wenn Sie eine Nur-Lese automatisch implementierte Eigenschaft deklarieren, indem Sie die Setter an private Einstellung:

public int MyProperty { get; private set; } 

der Compiler tut Flagge Alle " Set "als privat. Die Setter- und Getter-Methode sagt dasselbe.

public int MyProperty 
{ 
    [CompilerGenerated] 
    get 
    { 
     return this.<MyProperty>k__BackingField; 
    } 
    private [CompilerGenerated] 
    set 
    { 
     this.<MyProperty>k__BackingField = value; 
    } 
} 

zerlegt C# -Code von IL

So bin ich nicht sicher, warum der Rahmen beide erfordern die get; und setzen; auf einer automatisch implementierten Eigenschaft. Sie hätten die Set- und Setter-Methode einfach nicht schreiben können, wenn sie nicht mitgeliefert wurde. Aber es kann ein Problem mit dem Compiler-Level geben, das das schwierig macht, ich weiß es nicht.

Wenn Sie auf dem langen Weg suchen eine Nur-Lese-Eigenschaft erklärt:

public int myProperty = 0; 
public int MyProperty 
{ 
    get { return myProperty; } 
} 

Und dann demontierte Code aussehen. Der Setzer ist gar nicht da.

public int Test2 
{ 
    get 
    { 
     return this._test; 
    } 
} 

public int get_Test2() 
{ 
    return this._test; 
} 

zerlegt C# -Code von IL

+5

Die private set-Methode ist bei auto-properties erforderlich, da Sie den Wert sonst nie auf etwas festlegen könnten, was sinnlos wäre. Sie können den Setter von einer nicht automatischen Eigenschaft ausschließen, da das Hintergrundfeld eine Möglichkeit bietet, den Wert intern zu ändern. –

+0

Guter Punkt, das ist richtig. Da Sie bei Verwendung einer automatisch implementierten Eigenschaft keine private Variable haben, können Sie einen Wert festlegen, wenn dieser nicht vorhanden war. –

2

Nun, natürlich müssen Sie einen Weg zwischen den Feldern und Eigenschaften von disambiguating. Aber sind benötigte Schlüsselwörter wirklich notwendig? Zum Beispiel ist es klar, dass diese beiden Deklarationen unterschiedlich sind:

Das könnte funktionieren. Das heißt, es ist eine Syntax, für die ein Compiler denkbar wäre.

Aber dann kommen Sie zu einer Situation, in der ein leerer Block eine semantische Bedeutung hat. Das scheint prekär zu sein.

2

Da niemand erwähnt es ... Sie die Auto-Eigenschaft virtuellen machen könnte, und überschreiben sie:

public virtual int Property { get; set; } 

Wenn kein Satz get/war, wie es außer Kraft gesetzt werden würde? Beachten Sie, dass Sie override the getter and not the setter erlaubt:

public override int Property { get { return int.MinValue; } } 
2

Auch, weil seitdem C# 6.0 (in Visual Studio 2015, zum Zeitpunkt dieser Antwort in der Version ultimative Vorschau) können Sie eine wahre schreibgeschützte Eigenschaft implementieren können:

public string Name { get; } 
public string Name { get; } = "This won't change even internally"; 

... im Gegensatz zu derzeit unvollkommener Behelfslösung mit öffentlichen Getter/privater setter pair:

public string Name { get; private set; } 

public Constructor() { Name="As initialised"; } 
public void Method() { Name="This might be changed internally. By mistake. Or not."; } 

Beispiel der oben unter (zusammengestellt und executa ble online here).

using System; 

public class Propertier { 
    public string ReadOnlyPlease { get; private set; } 

    public Propertier() { ReadOnlyPlease="As initialised"; } 
    public void Method() { ReadOnlyPlease="This might be changed internally"; } 
    public override string ToString() { return String.Format("[{0}]",ReadOnlyPlease); } 
} 

public class Program { 
    static void Main() { 
     Propertier p=new Propertier(); 
     Console.WriteLine(p); 

//  p.ReadOnlyPlease="Changing externally!"; 
//  Console.WriteLine(p); 

     // error CS0272: The property or indexer `Propertier.ReadOnlyPlease' cannot be used in this context because the set accessor is inaccessible 
     // That's good and intended. 

     // But... 
     p.Method(); 
     Console.WriteLine(p); 
    } 
} 

Andere leckere Nachrichten über C# 6.0 verfügbar als offizielles Vorschau-Video here.

Verwandte Themen