2009-02-19 10 views
26

Kann ich eine Eigenschaft als "out" oder "ref" -Parameter übergeben, wenn nicht, warum nicht?Können Eigenschaften als "out" - oder "ref" -Parameter übergeben werden?

z.B.

Person p = new Person(); 

. . .

public void Test(out p.Name); 
+1

Bitte geben Sie Ihre Frage einen Sinn machen ... –

+4

Es macht genug Sinn, dass es eine vernünftige bekam Antwort –

+0

Hallo, eigentlich ist meine Frage: kann ich eine Eigenschaft als "out" oder "ref" -Parameter übergeben, wenn nicht dann y nicht? Beispiel. Person p = neue Person(); public void Test (aus p.Name); –

Antwort

36

Apologies für die kurze Antwort, aber nein, die Sprache C# Spezifikation verbietet es.

Sehen Sie diese answer zu einer anderen Frage, um zu sehen, was passiert, wenn Sie es versuchen. Es sagt auch, warum Sie die Eigenschaft nicht nur ein öffentliches Feld sein sollten, um die Einschränkung zu umgehen.

this helps

EDIT: Sie fragen, warum?

Sie übergeben eine Variable an einen out oder ref Parameter übergeben Sie tatsächlich die Adresse (oder Speicherort im Speicher) der Variablen. Innerhalb der Funktion weiß der Compiler, wo die Variable wirklich ist, und ruft und schreibt Werte an diese Adresse.

Eine Eigenschaft sieht wie ein Wert aus, aber es ist eigentlich ein Paar Funktionen, jede mit einer anderen Signatur. Um eine Eigenschaft zu übergeben, müssten Sie also tatsächlich zwei Funktionszeiger übergeben, einen für den get und einen für den Satz.

Das ist eine ganz andere Sache, eine Funktion zu übergeben, als die Adresse eines variablen

d.h. eine variable zwei Funktionszeiger die Adresse v.

aktualisieren
Warum danach nicht C# aussehen nur für uns?

Ich bin kein Eric Lippert, aber ich werde gehen an, warum

Was sollte die Signatur der Funktion sind rufen Sie sein?
Sagen wir, Sie möchten void MyFn(ref int i) anrufen, sollte das so bleiben, oder sollte es sich ändern, um zu sagen, dass wir auch Eigenschaften zulassen? Wenn es zu einer Syntax wie void MyFn(prop_ref int i) wird, dann ist das ziemlich nutzlos, Sie können Eigenschaften nicht an Bibliotheksfunktionen oder 3rd-Party-Code übergeben, der nicht mit dem speziellen prop_ref-Modifikator geschrieben wurde. Jedenfalls denke ich, dass du vorschlägst, dass es nicht anders sein sollte.

Jetzt sagen wir MyFn übergibt i an eine COM-Funktion oder WinAPI-Aufruf, die Adresse von i (d. H. Außerhalb .net, durch ref). Wenn es eine Eigenschaft ist, wie erhalten Sie die Adresse i? Es gibt möglicherweise keinen tatsächlichen Int unter der Eigenschaft, um die Adresse zu erhalten. Tun Sie was VB.Net macht?

Der Vb.Net-Compiler erkennt, wenn eine Eigenschaft als ByRef-Argument an eine Methode übergeben wird. An diesem Punkt deklariert er eine Variable, kopiert die Eigenschaft in die Variable, übergibt die Variable byref und kopiert dann nach dem Aufruf der Methode die Variable zurück in die Eigenschaft. d.h.

MyFunc(myObject.IntProperty) 

wird

Dim temp_i As Integer = myObject.IntProperty 
MyFunc(temp_i) 
myObject.IntProperty = temp_i 

Jede Eigenschaft Nebenwirkungen nicht passieren, bis MyFunc zurückkehrt, die alle möglichen Probleme verursachen können und zu sehr subtile Bugs führen.

In meiner bescheidenen Meinung ist die Vb.Net Lösung für dieses Problem auch gebrochen, also werde ich das als Antwort nicht akzeptieren.

Wie denken Sie, dass der C# -Compiler damit umgehen sollte?

+16

Das ist kaputt. C# ist keine Low-Level-Sprache, daher sollte ein 'Ref'-Parameter keine Adresse sein, sondern ein Paar Closures, ein Getter und ein Setter. Übergeben Sie eine lokale Variable als ref-Parameter, sollte die Sprache automatisch ein Getter/Setter-Paar erzeugen. Und all das sollte dem ahnungslosen Programmierer verborgen bleiben. – pyon

+0

@ Eduardo León: Ich habe meine Antwort aktualisiert. –

+1

@ EduardoLeón: Es gibt viele Dinge, die mit Adressen gemacht werden können, die mit Schließungen nicht gemacht werden können. Der richtige Weg, um Eigenschaften als Referenzen übergeben zu können, würde darin bestehen, eine Art von Eigenschaft zu definieren, die, statt einen Getter und Setter zu enthalten, eine Adresse auf kontrollierte Weise freilegt (zB eine Eigenschaft vom Typ T könnte eine Methode haben, die gegeben ist Ein Delegat, der einen Ref-Parameter vom Typ T akzeptiert, würde die Adresse des Backing-Feldes dieser Eigenschaft (oder eines anderen Speicherortes vom Typ T) an diesen Delegaten übergeben. – supercat

0

Stattdessen sollten Sie so etwas wie dieses

WhatEverTheType name; 

Test(out name); 

// Choose one of the following construction 

Person p = new Person(); 
p.Name = name; 

Person p = new Person(name); 
Person p = new Person(Name => name); 
+2

Ja. Aber ... ah, so viel mehr Code! – micahhoover

11

Andere haben erklärt tun, dass Sie dies in C# nicht tun kann. In VB.NET, Sie können dies tun, auch mit der Option streng/explizit auf:

Option Strict On 
Option Explicit On 
Imports System.Text 

Module Test 

    Sub Main() 
     Dim sb as new StringBuilder 
     Foo (sb.Length) 
    End Sub 

    Sub Foo(ByRef x as Integer) 
    End Sub 

End Module 

Der obige Code ist zu diesem C# -Code-Äquivalent:

using System.Text; 

class Test 
{ 
    static void Main() 
    { 
     StringBuilder sb = new StringBuilder(); 
     int tmp = sb.Length; 
     Foo(ref tmp); 
     sb.Length = tmp; 
    } 

    static void Foo(ref int x) 
    { 
    } 
} 

Ich persönlich bin froh, dass C# hat das nicht - es trübt die Gewässer ziemlich, insbesondere hinsichtlich des Werts der Eigenschaft, wenn der Parameter innerhalb der Methode gesetzt wird, aber dann eine Ausnahme ausgelöst wird.

EDIT: Wie beantragt, meine Argumentation, warum ich glaube, dass Eigenschaften in den Gewässern matschig. Wenn Sie eine normale Variable als Referenz übergeben, wird diese Variable jedes Mal ausgewertet, wenn sie in der Methode referenziert wird. Wenn sich der Wert aus irgendeinem Grund ändert (z. B. als Nebeneffekt einer anderen Arbeit in der Methode), wird diese Änderung sofort in der Methode sichtbar. Das ist nicht der Fall, wenn Sie eine Eigenschaft als Verweis in VB.NET übergeben: Der Eigenschaften-Getter wird einmal aufgerufen, und dann wird der Eigenschaften-Setter einmal aufgerufen. Es ist nicht so, als würden Sie reingehen "hier ist eine Eigenschaft - holen Sie und stellen Sie davon ein, wann immer Sie den Parameter verwenden."

Hier ist ein vollständiges Beispiel, wo ein Feld geht und eine ganz triviale Eigenschaft in .NET geben haben sehr unterschiedliche Ergebnisse:

Option Strict On 
Option Explicit On 
Imports System.Text 

Class Test 

    Dim counter as Integer 

    Property CounterProperty As Integer 
     Get 
      Return counter 
     End Get 
     Set (ByVal value as Integer) 
      counter = value 
     End Set 
    End Property 

    Sub Increment 
     counter += 1 
    End Sub 

    Shared Sub Main() 
     Dim t as new Test() 
     Console.WriteLine("Counter = {0}", t.counter) 
     t.Foo(t.counter) 
     Console.WriteLine("Counter = {0}", t.counter) 

     t.CounterProperty = 0 
     Console.WriteLine("CounterProperty = {0}", t.CounterProperty) 
     t.Foo(t.CounterProperty) 
     Console.WriteLine("CounterProperty = {0}", t.CounterProperty) 
    End Sub 

    Sub Foo(ByRef x as Integer) 
     x = 5 
     Increment 
     Increment 
     Increment 
     x += 1 
    End Sub 

End Class 
+2

Jon: Wenn es dir nichts ausmacht, kannst du deine Gedanken über "die Gewässer trüben" erklären, ich verstehe nicht, warum du denkst, dass das Übergeben von Eigenschaften in Ref-Parameter eine besonders schlechte Idee ist (ich sage nicht, dass sie es sind) eine gute Idee). Danke Kumpel. –

2

Ein weiteren Grund, dies nicht zulässig, weil der Schiedsrichter und out-Parameter ist lesbar und Innerhalb einer Methode schreibbar, während eine Eigenschaft schreibgeschützt sein kann.

Was nun, wenn Sie das tun können?

Test(out p.Name);  

public void Test(out string name) 
{ 
    name = "someone else"; 
} 

Sie sind jetzt nicht Sie, sondern jemand anderes, aber das ist gegen den Vertrag, den Sie mit get gemacht nur Eigenschaft Name (wenn überhaupt daran gearbeitet). Dies ist der gleiche Fall bei schreibgeschützten Mitgliedsfeldern der Klasse, deren Referenz Sie nicht übergeben können.

Person 
{ 
    public readonly string name = "me"; 
} 

Test(out p.name); //not possible. 

C# sein kann mit einem Nur-Lese/write Argumente für eine Methode kann kommen:

public void Test(out settable string name, gettable int count, bool whatever) 
{ 
    name = "someone else"; 
} 

Test(out p.Name, 0, true); // doesnt compile since p.Name is readonly. 
+0

Ich denke, du überschwingst diesen Weg zu sehr. Es würde einfach nicht erlauben, dass get-only-Eigenschaften durch ref oder out übergeben werden, genauso wie es bei schreibgeschützten Feldern mit einem Fehler nicht passieren kann. –

Verwandte Themen