C#扩展方法可以访问私有变量吗?


Answers:


75

不可以。在扩展方法中,您可以像在某些实用工具类中的“常规”静态方法中一样进行操作。

所以这个扩展方法

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

等效于这样的静态辅助方法(至少关于您可以访问的内容):

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

(当然,您可以在这两种方法中使用一些反射来访问私有成员。但是我想这不是这个问题的重点。)


4
+1。顺便说一句,您可以使用私有扩展方法。odetocode.com/Blogs/scott/archive/2009/10/05/上有一篇不错的文章。扩展方法还可以访问其静态实用程序类的私有静态成员。
TrueWill

3
即使将其标记为C#,它也适用于提供对扩展方法的支持的任何.NET语言。
Scott Dorman

1
@TrueWill-但是由于它们必须是静态,非嵌套,非泛型类型,因此它们实际上不能对任何对象的变量进行私有访问。internal访问,当然-但不是private
马克·格雷韦尔

-1我不明白这里的支持...这个答案很容易引起误解。普通的公共静态方法可以访问类内部的私有方法,而扩展方法则不能。以下代码完全有效并可以编译:公共类Foo {private bool _variable; 公共静态布尔GetVariable(Foo foo){return foo._variable; }
扎伊德·马苏德

2
@ZaidMasud-它说它与“在某些实用程序类中”的静态方法相同,而不是在同一类中。

23

不,它不能。

但是,您将有兴趣知道其他答案是不正确的,因为它们说普通的静态方法无法访问私有字段。静态方法可以访问其自己类中的私有非静态成员字段。以下代码完全有效,并显示了访问私有字段的静态方法:

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. 为什么不允许嵌套类中的扩展方法定义?

11

没有:

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

6

使用反射

不推荐使用,但是您可以使用其他扩展方法访问任何类型的任何私有变量,如下所示:

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

如果您拥有要扩展的类,则始终将类声明为局部,然后扩展该类并可以访问其他文件中的所有私有成员……但是您实际上并不会使用扩展方法。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.