扩展方法是否类似于C#中的“new”关键字方法?

3

扩展方法和继承之间是否存在关联?或者说,扩展方法是否类似于在C#中使用new关键字?


欢迎来到 Stack Overflow。如果您能解释一下 new 关键字的三个主要含义中您指的是哪一个,那将对我们有所帮助:类实例化(例如 new House())、方法覆盖(例如当继承一个包含 Activate 方法的类时写成 new public void Activate())、或者泛型约束中的 new()(例如 where T: new())。 - Abel
方法重写(如新的公共void) - Dhananjay
4个回答

9

两个问题都是否定的。扩展方法实际上是一个以扩展操作对象为第一个参数的方法。

new关键字用于为类的实例分配资源。扩展方法作用于实例,但不能作为新实例的替代,因为它需要一个实例(或该类型的null)作为第一个参数。

考虑以下示例:

public static class StringExtensions
{
    public static string Reverse(this string _this)
    {
        // logic to reverse the string
    }
}

你可以通过两种方式调用这个静态方法:
// as an extension method:
string s = "hello world";
string t = s.Reverse();

// as a static method invocation:
string t = StringExtensions.Reverse(s);

无论哪种情况,编译器都会将MSIL中的第二个调用映射为调用。编译后,您将无法通过静态对应项识别扩展方法,而不使用this关键字。 总结一下:
  • 扩展方法不是类的一部分
  • 扩展方法与继承没有关系,实际上它们是静态方法,不会被继承
  • 扩展方法不能像new关键字那样实例化类(但在方法内部,您当然可以实例化类)。
  • 扩展方法可以操作null,而否则该类的方法会引发NullReferenceException。这源于实例只是静态方法中的第一个参数。
  • 可以扩展密封类(如上面的string),这在继承中是不可能的(您不能从密封类派生)。
编辑:
Tigran和Floran暗示这个问题是关于new修饰符的,我补充说这甚至可能涉及新的泛型约束
扩展方法与new关键字的任一含义都没有关系。但是,以下是一些相关想法。我希望它不会让事情更加混乱。如果是这样,请坚持上面“编辑”部分的内容;)
  • On the new modifier:

    • the new modifier is used to hide existing methods. An extension method can never hide existing methods, because the declaration is a static method. You will not even get a compile time warning or error when you do.
    • The new modifier requires that the method (or property) already exists and is accessible. An extension method can only work if the method with the same signature does not already exist.
    • The new modifier operates on an extension of the class through inheritance, i.e., every method is already inherited. An extension method operates on an instance of the class and has no inheritance relationship with the class.
       
  • On the new generic constraint:

    • the constraint limits the allowed generic types to those with an accessible parameterless constructor. An extension method has nothing to do with generics.
    • an extension method itself van be generic and the parameters (i.e., the allowed classes it operates on) can be limited by the new generic constraint:

      // this ext. method will only operate on classes that inherit 
      // from ICollectible and have a public parameterless constructor
      public static int CalculateTotal<T>(this T _collectible)
          where T : ICollectible, new()
      {
          // calculate total
      }
      

3
我认为问题是关于“new modifier”的,就像habib.osu的回答中所说的那样,而不是关于“new operator”的。除此之外,我同意你的回答。 - Florin Dumitrescu
“new” 关于成员变量的遮蔽问题。 - Tigran
@Florin / @Tigran:虽然我没有从问题中读出这一点,但这是可能的。在这方面,它也可能涉及到通用约束“new()”。只有RDK可以解释清楚。我会更新我的答案。 - Abel
@Abel:问题在于,阴影处理可能会被轻易地与重载混淆,但我认为 new object() 不会被误解为面向对象编程概念。 - Tigran
@Tigran:现在你把重载带到了讨论中;)。这是另一个但紧密相关的角度。重载是关于具有相同名称的不同签名,而 new 只能隐藏具有 完全 相同签名的方法。但我同意,这比我最初写的更可能是 OP 的意思。 - Abel
@Abel:抱歉,Abel,是我错了。我的意思是覆盖,只是打错字了……愚蠢的错误。 - Tigran

3
不,扩展方法只是扩展已有类的功能。
扩展方法使您能够“添加”方法到现有类型中,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。
请参见MSDN on Extension Methods (C# Programming Guide)new关键字需要允许您从基类override非虚拟和静态方法。
public class A
{
   public virtual void One();
   public void Two();
}

public class B : A
{
   public override void One();
   public new void Two();
}

B b = new B();
A a = b as A;

a.One(); // Calls implementation in B
a.Two(); // Calls implementation in A
b.One(); // Calls implementation in B
b.Two(); // Calls implementation in B

查看关于newoverride的这个链接


“覆盖基类中的非虚拟和静态方法。” 不可以,因为静态方法本来就不会被继承。而且也不行,因为您还可以在虚拟方法上使用 new,这与使用 override 覆盖略有不同。 - Abel

1
不是的。扩展方法只是一个语法糖,它对应一个单独的静态类,该类以其第一个参数为“扩展”的类型对象作为输入。它与继承没有任何关系。该方法仅能访问“扩展”类的公共成员,就像任何其他类一样。

0

扩展方法与继承或new关键字(或构造函数)无关。如果您想为一个没有源代码的类添加一些功能,它允许您编写更好的代码。如果您有源代码,那么更改源代码通常更好。

例如,您可能想要能够执行此操作:

string text = "this is my string";
int count = text.WordCount();

这个方法在String类中不存在,你需要像这样做:

string text = "this is my string";
int count = MyCommon.WordCount(text);

这里的WordCount()是您某些常用库中的静态方法。

但是使用扩展方法,您还可以执行以下操作:

public static class MyExtensions
{
    public static int WordCount(this String str)
    {
        return str.Split(new char[] { ' ', '.', '?' }, 
                         StringSplitOptions.RemoveEmptyEntries).Length;
    }
}

然后text.WordCount()就像在String类中定义的普通方法一样工作。这只是使使用起来更加方便。

代码取自这里,我建议也阅读一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接