web-dev-qa-db-ja.com

C#拡張メソッドはプライベート変数にアクセスできますか?

拡張メソッドを使用してオブジェクトのプライベート変数にアクセスすることは可能ですか?

67
Geo

いいえ。いくつかのユーティリティクラスの「通常の」静的メソッドと同じように、拡張メソッドで行うことができます。

したがって、この拡張メソッド

public static void SomeMethod(this string s)
{
    // do something with 's'
}

このような静的ヘルパーメソッドと同等です(少なくともアクセスできるものに関して):

public static void SomeStringMethod(string s)
{
    // do something with 's'
}

(もちろん、どちらの方法でもリフレクションを使用してプライベートメンバーにアクセスできます。しかし、これはこの質問のポイントではないと思います。)

71
M4N

いいえ、できません。

ただし、通常の静的メソッドはプライベートフィールドにアクセスできないという他の答えが間違っていることを知りたいと思うでしょう。 静的メソッドは、独自のクラスの非静的メンバーフィールドにアクセスできます。次のコードは完全に有効で、静的フィールドにアクセスする静的メソッドを示しています。

public class Foo
{
    private bool _field;

    public static bool GetField(Foo foo)
    {
        return foo._field;
    }
}

さあ...質問に戻りましょう。他の回答が存在すると主張する静的メソッドとの(存在しない) "同等性"を考えると、拡張メソッドは同じことを行えるはずだと考えるかもしれません。ただし、ネストされたクラス内で拡張メソッドを宣言することはできません。したがって、次のことをしようとすると:

public class Foo
{
    private bool _field;

    public static class Extensions
    {
        public static bool GetField(this Foo foo)
        {
            return foo._field;
        }
    }
}

コンパイルエラーが表示されます

拡張メソッドはトップレベルの静的クラスで定義する必要があります。拡張機能はネストされたクラスです

興味深いことに、thisキーワードを削除すると、コードが正常にコンパイルされることに注意してください。この理由は次のとおりです。

  1. なぜ拡張メソッドは、ネストされていない非ジェネリックな静的クラスでのみ許可されているのですか?
  2. ネストされたクラスで拡張メソッドの定義を許可しない理由
23
Zaid Masud

番号:

public class Foo
{
    private string bar;
}

public static class FooExtensions
{
    public static void Test(this Foo foo)
    {
        // Compile error here: Foo.bar is inaccessible due to its protection level  
        var bar = foo.bar;
    }
}
11
Darin Dimitrov

いいえ、パブリックプロパティまたはプロキシパターンを介して何らかのアクセスを許可しない限り。

3

リフレクションを使用する

推奨されませんが、次のような別の拡張メソッドを使用して、任意のタイプのプライベート変数にアクセスできます。

public static T GetFieldValue<T>(this object obj, string name) {
    var field = obj.GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    return (T)field?.GetValue(obj);
}

そして、任意のタイプのプライベートフィールドにアクセスします。

Foo foo = new Foo();
string privateBar = foo.GetFieldValue<string>("_bar");
2
Bruno Zell

拡張するクラスを所有している場合は、常にクラスを部分的に宣言し、クラスを拡張して別のファイルのすべてのプライベートメンバーにアクセスできます。しかし、実際には拡張メソッドを使用しません。

2
Rimbimbambo

拡張メソッドは基本的に静的メソッドであるため、アクセスできるのは、拡張メソッドが呼び出されるインスタンスのパブリックメンバーだけです。

0
Abhijeet Patel