プロパティが暗黙的にデリゲートに変換できないのはなぜですか


9

C#のプロパティは、実際の単純な古いメソッドにコンパイルされることは誰でも知っています。しかし、method(-group)とは異なり、Func<T>orまたはAction<T>(getterおよびsetter)のようなデリゲートを期待する他のメソッドへの引数としてそれらを与えることはできません。これを禁止する特別なものはありますか、それともメソッドグループをデリゲートに暗黙的に変換可能にするときに「無料」で提供されなかった機能だけですか?

コード例:

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);
}

私は推測していた場合、我々は単に書き込みの余分なファズ行うことができたときに、私が言うと思いプロパティ自体に呼び出しや参照を区別する構文の問題は解決する価値がなかったこと() => MyClass.Xかをx => MyClass.X = x


彼らはどちらを呼びますか?取得または設定
Ewan

私の考えは、それはデリゲートのタイプに依存すると思います。setであるActiongetされFunc、例えば
サラ

1
参考までに、インラインデリゲートを使用してgetter / setterを渡す構文delegate {return SomeProperty}ゲッターを渡します。delegate(YourType value) {SomeProperty = value}セッターを渡します。1つまたは2つの場所のみを渡す必要がある場合、これは、他の方法で作成するラップされたメソッドの省略形です。
ToolmakerSteve 2018

FWIW、ゲッターとセッターの両方を渡したい場合は、代わりにInterfaceそのプロパティでを定義し、呼び出されたメソッドのシグネチャを変更して、そのインターフェイスをパラメーターとして受け取ることを検討してください。
ToolmakerSteve 2018

回答:


7

問題は、「MyClass.X」が明確に定義された意味を持っていることです。これは、プロパティ「X」でゲッターを呼び出すことです。注意すべき重要なことは、メソッドが呼び出されていても、ブラケットは必要ないということです。

一方、コード例で "Foo"を呼び出す場合など、通常のメソッドを呼び出す場合は、メソッドを実行する必要があることを示すために角かっこ必要です。メソッドへの参照を渡したい場合は、ブラケットを除外します(以下の例を参照)。

これは、メソッドを参照するときに曖昧さがないことを意味します。つまり、メソッドをすぐに実行する(必要な引数を渡し、括弧を含める)か、メソッドを引数として渡します(括弧なし)。

プロパティのゲッターまたはセッターでは、角括弧は「ゲッター/セッターをすぐに実行する」ことを意味していません。プロパティgetter / setterもメソッドグループとして渡すことができる場合、「x.Name」は「Name getterを今すぐ実行する」ことを意味し、「Name getterをメソッドグループとして渡す」ことを意味する場合があります。"x.Name"が文字列を期待する関数に渡されているように見える(この場合、ゲッターが実行される)か、または渡されているように見えるかどうかに基づいて、コンパイラを明確にすることができる場合があります。 Func <string>を期待する関数(この場合、getterはメソッドグループとして渡されます)、C#言語チームは、このような混乱の可能性があるシナリオを回避しようとします。

using System;

namespace Example
{
    public static class Program
    {
        static void Main()
        {
            ValueWriter(1); // Execute ValueWriter (because brackets)
            Bar(ValueWriter); // Pass ValueWriter as an action (no brackets)
        }

        private static void Bar(Action<int> f)
        {
            f(2);
        }

        private static void ValueWriter(int value)
        {
            Console.WriteLine("Value is " + value);
        }
    }
}

5

文法とコンパイラがどのように機能するかの基本的な理由により、それは不可能です。

式は「ボトムアップ」でMyClass.X評価されます。つまり、この結果が関数の引数として渡される前に、式がint値評価されます。あなたの提案は、式がゲッター呼び出しとして解釈されるべきか、ゲッターメソッド自体への参照として解釈されるべきかをコンテキスト(パラメーターのタイプ)が指示する可能性があることを示唆しているようです。これは明確な方法で行うことはできません。プロパティ自体のタイプがまたはの場合はどうなりますFuncAction?そして、どのようvar x = MyClass.Xに解釈されますか?メソッドにintor Funcまたはor Actionパラメータのオーバーロードがある場合はどうなりますか?

これらのあいまいさを解決するには、構文レベルでの区別が必要です。たとえば、次のようなtypeof演算子のように、文法で特別にサポートされている演算子です。

Foo(getterof(MyClass.X));

しかし、これはそのような限られた利点のある機能にとってははるかに問題になります。


はい、必要に応じて、微妙に操作することができますが、決定不可能性はショーストッパーです。
Deduplicator

2

Foo.Do()呼び出しを意味しFoo.Do、代理人であることは問題ありません。

Foo.Xプロパティと、微妙なコンテキストの違いに依存するゲッターデリゲートおよびセッターデリゲートを混在させることは、混乱を招きます。圧倒的ではない優れた機能は、C#にも組み込まれていません。これは実際には悪い機能のようです。短いコードを1度書きたい場合は、Perlを試してください。

C#で必要なものを明確に表現する方法は既に存在しますが、問題はありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.