>  기사  >  백엔드 개발  >  C# 매개변수의 의미(확장 방법)

C# 매개변수의 의미(확장 방법)

黄舟
黄舟원래의
2017-02-18 10:24:444337검색


확장 메서드를 사용하면 새 파생 유형을 생성하거나 재컴파일하거나 원래 유형을 수정하지 않고도 기존 유형에 메서드를 "추가"할 수 있습니다. 확장 메소드는 특별한 종류의 정적 메소드이지만 확장 유형의 인스턴스 메소드처럼 호출될 수 있습니다. C# 및 Visual Basic으로 작성된 클라이언트 코드의 경우 확장 메서드를 호출하는 것과 해당 형식에 실제로 정의된 메서드를 호출하는 것 사이에는 큰 차이가 없습니다.

가장 일반적인 확장 방법은 기존 System.Collections.IEnumerable 및 System.Collections.Generic.IEnumerable 유형에 쿼리 기능을 추가하는 LINQ 표준 쿼리 연산자입니다. 표준 쿼리 연산자를 사용하려면 먼저 다음을 사용하세요. System.Linq 지시문은 이를 범위에 넣습니다. 그러면 IEnumerable을 구현하는 모든 유형에는 GroupBy, OrderBy, Average 등과 같은 인스턴스 메서드가 있는 것으로 보입니다. IEnumerable(예: List 또는 Array) 유형의 인스턴스 뒤에 "점"을 입력하면 다음을 수행할 수 있습니다. 이러한 추가 메서드는 IntelliSense 문 완성에 표시됩니다.

다음 예에서는 정수 배열에서 표준 쿼리 연산자 OrderBy 메서드를 호출하는 방법을 보여줍니다. 괄호 안의 표현식은 람다 표현식입니다. 많은 표준 쿼리 연산자는 람다 표현식을 매개변수로 사용하지만 이는 확장 메서드의 요구 사항은 아닙니다. 자세한 내용은 Lambda를 참조하세요. 식(C# 프로그래밍 가이드).

C#



class ExtensionMethods2    
{    static void Main()
    {            
        int[] ints = { 10, 45, 15, 39, 21, 26 };        var result = ints.OrderBy(g => g);        foreach (var i in result)
        {
            System.Console.Write(i + " ");
        }           
    }        
}//Output: 10 15 21 26 39 45


확장 방법은 다음과 같습니다. 정적 메서드로 정의되지만 인스턴스 메서드 구문을 통해 호출됩니다. 첫 번째 매개변수는 메소드가 작동하는 유형을 지정하며 매개변수 앞에는 this 수정자가 붙습니다. 확장 메서드는 using 지시어를 사용하여 네임스페이스를 소스 코드로 명시적으로 가져오는 경우에만 범위 내에 있습니다.

다음 예제에서는 System.String 클래스에 정의된 확장 메서드를 보여줍니다. 중첩되지 않고 제네릭이 아닌 정적 클래스 내부에 정의되어 있습니다.

C#


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


using 지시문을 사용하여 WordCount 확장 메서드를 범위:

using ExtensionMethods;


而且,可以使用以下语法从应用程序中调用该扩展方法:

string s = "Hello Extension Methods";
int i = s.WordCount();


在代码中,可以使用实例方法语法调用该扩展方法。 但是,编译器生成的中间语言 (IL) 会将代码转换为对静态方法的调用。 因此,并未真正违反封装原则。 实际上,扩展方法无法访问它们所扩展的类型中的私有变量。

有关详细信息,请参阅如何:实现和调用自定义扩展方法(C# 编程指南)。

通常,你更多时候是调用扩展方法而不是实现你自己的扩展方法。 由于扩展方法是使用实例方法语法调用的,因此不需要任何特殊知识即可从客户端代码中使用它们。 若要为特定类型启用扩展方法,只需为在其中定义这些方法的命名空间添加 using 指令。 例如,若要使用标准查询运算符,请将此 using 指令添加到代码中:


using System.Linq;


(你可能还必须添加对 System.Core.dll 的引用。)你将注意到,标准查询运算符现在作为可供大多数 IEnumerable 类型使用的附加方法显示在 IntelliSense 中。

C# 매개변수의 의미(확장 방법)C# 매개변수의 의미(확장 방법)

尽管标准查询运算符没有显示在 String 的 IntelliSense 中,但它们仍然可用。


컴파일 시 바인딩 확장 메서드

확장 메서드를 사용하여 클래스 또는 인터페이스를 확장할 수 있습니다. , 그러나 확장 메서드는 재정의될 수 없습니다. 인터페이스 또는 클래스 메서드와 이름 및 서명이 동일한 확장 메서드는 호출되지 않습니다. 컴파일 시 확장 메서드는 항상 유형 자체에 정의된 인스턴스 메서드보다 우선순위가 낮습니다. 즉, 유형에 Process(int i) 메서드와 동일한 시그니처를 가진 확장 메서드가 있는 경우 컴파일러는 항상 해당 인스턴스 메서드에 바인딩합니다. 컴파일러는 메서드 호출을 발견하면 먼저 해당 유형의 인스턴스 메서드 중에서 일치하는 메서드를 찾습니다. 일치하는 메서드가 없으면 컴파일러는 해당 유형에 정의된 확장 메서드를 검색하고 찾은 첫 번째 확장 메서드에 바인딩합니다. 다음 예에서는 컴파일러가 바인딩할 확장 메서드나 인스턴스 메서드를 결정하는 방법을 보여줍니다.

다음 예는 C# 컴파일러가 호출 여부를 결정하는 방법을 보여줍니다. 메소드 유형의 인스턴스 메소드 또는 확장 메소드에 바인딩할 때 따라야 할 규칙입니다. 정적 클래스 Extensions에는 IMyInterface를 구현하는 모든 유형에 대해 정의된 확장 메서드가 포함되어 있습니다. 클래스 A, B, C 모두 이 인터페이스를 구현합니다.

MethodB 확장 메서드는 이름과 서명이 해당 클래스에서 이미 구현된 메서드와 정확히 일치하기 때문에 호출되지 않습니다.

컴파일러가 일치하는 시그니처가 있는 인스턴스 메서드를 찾을 수 없으면 일치하는 확장 메서드(해당 메서드가 있는 경우)에 바인딩합니다.

C#


// Define an interface named IMyInterface.namespace DefineIMyInterface
{    using System;    public interface IMyInterface
    {        // Any class that implements IMyInterface must define a method
        // that matches the following signature.
        void MethodB();
    }
}// Define extension methods for IMyInterface.namespace Extensions
{    using System;    using DefineIMyInterface;    // The following extension methods can be accessed by instances of any 
    // class that implements IMyInterface.
    public static class Extension
    {        public static void MethodA(this IMyInterface myInterface, int i)
        {
            Console.WriteLine
                ("Extension.MethodA(this IMyInterface myInterface, int i)");
        }        public static void MethodA(this IMyInterface myInterface, string s)
        {
            Console.WriteLine
                ("Extension.MethodA(this IMyInterface myInterface, string s)");
        }        // This method is never called in ExtensionMethodsDemo1, because each 
        // of the three classes A, B, and C implements a method named MethodB
        // that has a matching signature.
        public static void MethodB(this IMyInterface myInterface)
        {
            Console.WriteLine
                ("Extension.MethodB(this IMyInterface myInterface)");
        }
    }
}// Define three classes that implement IMyInterface, and then use them to test// the extension methods.namespace ExtensionMethodsDemo1
{    using System;    using Extensions;    using DefineIMyInterface;    class A : IMyInterface
    {        public void MethodB() { Console.WriteLine("A.MethodB()"); }
    }    class B : IMyInterface
    {        public void MethodB() { Console.WriteLine("B.MethodB()"); }        
    public void MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }
    }    class C : IMyInterface
    {        public void MethodB() { Console.WriteLine("C.MethodB()"); }        
    public void MethodA(object obj)
        {
            Console.WriteLine("C.MethodA(object obj)");
        }
    }    class ExtMethodDemo
    {        static void Main(string[] args)
        {            // Declare an instance of class A, class B, and class C.
            A a = new A();
            B b = new B();
            C c = new C();            // For a, b, and c, call the following methods:
            //      -- MethodA with an int argument
            //      -- MethodA with a string argument
            //      -- MethodB with no argument.

            // A contains no MethodA, so each call to MethodA resolves to 
            // the extension method that has a matching signature.
            a.MethodA(1);           // Extension.MethodA(object, int)
            a.MethodA("hello");     // Extension.MethodA(object, string)

            // A has a method that matches the signature of the following call
            // to MethodB.
            a.MethodB();            // A.MethodB()

            // B has methods that match the signatures of the following
            // method calls.
            b.MethodA(1);           // B.MethodA(int)
            b.MethodB();            // B.MethodB()

            // B has no matching method for the following call, but 
            // class Extension does.
            b.MethodA("hello");     // Extension.MethodA(object, string)

            // C contains an instance method that matches each of the following
            // method calls.
            c.MethodA(1);           // C.MethodA(object)
            c.MethodA("hello");     // C.MethodA(object)
            c.MethodB();            // C.MethodB()
        }
    }
}/* Output:
    Extension.MethodA(this IMyInterface myInterface, int i)
    Extension.MethodA(this IMyInterface myInterface, string s)
    A.MethodB()
    B.MethodA(int i)
    B.MethodB()
    Extension.MethodA(this IMyInterface myInterface, string s)
    C.MethodA(object obj)
    C.MethodA(object obj)
    C.MethodB()
 */

通用准则

通常,建议你只在不得已的情况下才实现扩展方法,并谨慎地实现。 只要有可能,必须扩展现有类型的客户端代码都应该通过创建从现有类型派生的新类型来达到这一目的。 有关详细信息,请参阅继承(C# 编程指南)。

在使用扩展方法来扩展你无法更改其源代码的类型时,你需要承受该类型实现中的更改会导致扩展方法失效的风险。

如果你确实为给定类型实现了扩展方法,请记住以下几点:

  • 如果扩展方法与该类型中定义的方法具有相同的签名,则扩展方法永远不会被调用。

  • 在命名空间级别将扩展方法置于范围中。 例如,如果你在一个名为 Extensions 的命名空间中具有多个包含扩展方法的静态类,则这些扩展方法将全部由 using Extensions; 指令置于范围中。

针对已实现的类库,不应为了避免程序集的版本号递增而使用扩展方法。 如果要向你拥有源代码的库中添加重要功能,应遵循适用于程序集版本控制的标准 .NET Framework 准则。 有关详细信息,请参阅程序集版本控制。

 以上就是C# 参数带this是什么意思(扩展方法)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.