Wir alle wissen, dass Eigenschaften in C # nach einfachen alten Methoden kompiliert werden. Im Gegensatz zu Methoden (-gruppen) können sie jedoch nicht als Argumente für andere Methoden angegeben werden, die einen Delegaten wie ein Func<T>
oder Action<T>
(Getter und Setter) erwarten . Gibt es etwas Besonderes, das dies verbietet, oder ist es nur eine Funktion, die nicht "kostenlos" war, wenn Methodengruppen implizit in Delegate konvertierbar gemacht wurden?
Beispielcode:
public class MyClass
{
public static int X { get; set; }
}
private static void Foo<T>(Func<T> f)
{
Console.WriteLine(f());
}
private static void Bar<T>(Action<T> f)
{
f(default(T));
}
private static void Test()
{
// neither of these lines compile, even with an explicit type-cast.
Foo(MyClass.X);
Bar(MyClass.X);
}
Wenn ich raten müsste, würde ich sagen, dass das syntaktische Problem der Unterscheidung zwischen Aufrufen und Verweisen auf die Eigenschaft selbst keine Lösung wert war, wenn wir nur den zusätzlichen Fuzz des Schreibens () => MyClass.X
oder x => MyClass.X = x
.
c#
properties
delegates
Sara
quelle
quelle
set
ist einAction
undget
ist einFunc
zum Beispieldelegate {return SomeProperty}
geht an Getter vorbei;delegate(YourType value) {SomeProperty = value}
Setter passiert. Wenn Sie nur ein oder zwei Stellen übergeben müssen, ist dies eine Abkürzung für die umschlossenen Methoden, die Sie sonst erstellen würden.Interface
mit dieser Eigenschaft definieren und die Signatur der aufgerufenen Methode ändern, um diese Schnittstelle als Parameter zu verwenden.Antworten:
Das Problem ist, dass "MyClass.X" eine genau definierte Bedeutung hat, nämlich den Getter für die Eigenschaft "X" aufzurufen. Es ist wichtig zu beachten, dass trotz des Aufrufs einer Methode keine Klammern erforderlich sind.
Auf der anderen Seite, wenn eine reguläre Methode aufrufen, wenn Sie beispielsweise „Foo“ in Ihrem Beispiel - Code aufrufen, Klammern sind erforderlich , um anzuzeigen , dass das Verfahren ausgeführt werden soll. Wenn Sie einen Verweis auf eine Methode übergeben möchten, schließen Sie die Klammern aus (siehe Beispiel unten).
Dies bedeutet, dass beim Verweisen auf eine Methode keine Mehrdeutigkeit besteht - entweder führen Sie sie sofort aus (Übergabe aller erforderlichen Argumente und einschließlich Klammern) oder Sie übergeben die Methode als Argument (keine Klammern).
Bei einem Property Getter oder Setter bedeutet keine Klammer bereits "Getter / Setter sofort ausführen". Wenn der Property Getter / Setter auch als Methodengruppe übergeben werden könnte, würde "x.Name" manchmal "Name Getter jetzt ausführen" und manchmal "Übergeben des Namens Getter als Methodengruppe" bedeuten. Möglicherweise ist es möglich, den Compiler so zu ändern, dass er eindeutig ist, je nachdem, ob "x.Name" an eine Funktion übergeben wird, die eine Zeichenfolge erwartet (in diesem Fall würde der Getter ausgeführt) oder ob er an übergeben wird Als Funktion, die einen Func <string> erwartet (in diesem Fall würde der Getter als Methodengruppe übergeben), versucht das C # -Sprachteam, diese Art von möglicherweise verwirrenden Szenarien zu vermeiden.
quelle
Aufgrund der Grundlagen der Funktionsweise von Grammatik und Compiler ist dies nicht möglich.
Ausdrücke werden "bottom up"
MyClass.X
ausgewertet, dh der Ausdruck wird auf seinen int-Wert ausgewertet, bevor dieses Ergebnis als Argument für die Funktion eingegeben wird. Ihr Vorschlag scheint darauf hinzudeuten, dass der Kontext - der Typ des Parameters - bestimmen könnte, ob der Ausdruck als Getter-Aufruf oder als Referenz zur Getter-Methode selbst interpretiert werden soll. Dies ist nicht eindeutig möglich. Was ist, wenn der Typ der Immobilie selbst einFunc
oder istAction
? Und wie wirdvar x = MyClass.X
das interpretiert? Was ist, wenn die Methode Überladungen mit entwederint
oderFunc
oderAction
Parametern aufweist?Um diese Mehrdeutigkeiten aufzulösen, benötigen Sie eine Unterscheidung auf Syntaxebene, z. B. einen Operator mit besonderer Unterstützung in der Grammatik wie den
typeof
Operator, z.Dies wird jedoch für eine Funktion mit solch begrenztem Nutzen viel zu viel Mühe bedeuten.
quelle
Foo.Do()
Das heißt, der Aufruf und dasFoo.Do
Sein des Delegierten ist in Ordnung.Foo.X
Es ist verwirrend , sowohl die Eigenschaft als auch der Getter-Delegierte und der Setter-Delegierte zu sein, abhängig von subtilen Kontextunterschieden. Gute Funktionen, die nicht überwältigend gut sind, kommen nicht einmal in C #, dies scheint eine wirklich schlechte zu sein. Wenn Sie einmal kurz Code schreiben möchten, versuchen Sie es mit Perl.Es gibt bereits eine Möglichkeit, klar auszudrücken, welche Sie in C # benötigen. Ich sehe das Problem nicht.
quelle