확장 방법의 장점은 무엇입니까? [닫은]
C #의 "믿지 않는"사람이 확장 메서드의 목적이 무엇인지 물었습니다. 그런 다음 이미 정의 된 개체에 새 메서드를 추가 할 수 있다고 설명했습니다. 특히 원본 개체에 대한 소스를 소유 / 제어하지 않는 경우 더욱 그렇습니다.
그는 "왜 자신의 수업에 메소드를 추가하지 않습니까?"라고 말했습니다. 우리는 (좋은 방법으로) 빙글 빙글 돌았습니다. 내 일반적인 반응은 이것이 도구 벨트의 또 다른 도구라는 것입니다. 그의 반응은 도구의 쓸모없는 낭비라는 것입니다. 그러나 나는 더 "깨달은"대답을 얻을 것이라고 생각했습니다.
자신의 클래스에 추가 된 메서드를 사용할 수 없었거나 사용해서는 안되는 확장 메서드를 사용한 몇 가지 시나리오는 무엇입니까?
확장 메서드는 코드를 작성할 때 많은 도움이된다고 생각합니다. 기본 유형에 확장 메서드를 추가하면 지능적으로 빠르게 얻을 수 있습니다.
파일 크기 를 형식화 할 형식 공급자가 있습니다 . 그것을 사용하려면 다음과 같이 작성해야합니다.
Console.WriteLine(String.Format(new FileSizeFormatProvider(), "{0:fs}", fileSize));
다음과 같이 작성할 수있는 확장 메서드 만들기 :
Console.WriteLine(fileSize.ToFileSize());
더 깨끗하고 간단합니다.
확장 메서드 의 유일한 장점은 코드 가독성입니다. 그게 다야.
확장 메서드를 사용하면 다음을 수행 할 수 있습니다.
foo.bar();
대신 :
Util.bar(foo);
이제 C #에는 이와 같은 많은 것들이 있습니다. 즉, C #에는 사소 해 보이고 그 자체로는 큰 이점이없는 많은 기능이 있습니다. 그러나 이러한 기능을 함께 결합하기 시작하면 부분의 합보다 조금 더 큰 것을 보게됩니다. 확장 메서드가 없으면 LINQ 쿼리를 거의 읽을 수 없으므로 LINQ는 확장 메서드에서 큰 이점을 얻습니다. LINQ는 확장 메서드 없이는 가능 하지만 실용적이지는 않습니다.
확장 메서드는 C #의 부분 클래스와 매우 유사합니다. 그 자체로는별로 도움이되지 않고 사소 해 보입니다. 그러나 생성 된 코드가 필요한 클래스로 작업을 시작하면 부분 클래스가 훨씬 더 이해되기 시작합니다.
툴링을 잊지 마세요! Foo 유형에 확장 메서드 M을 추가하면 Foo의 인텔리 센스 목록에 'M'이 표시됩니다 (확장 클래스가 범위 내에 있다고 가정). 이렇게하면 MyClass.M (Foo, ...)보다 'M'을 훨씬 쉽게 찾을 수 있습니다.
하루가 끝나면 다른 정적 방법에 대한 통사론 적 설탕이지만 집을 사는 것과 같습니다 : '위치, 위치, 위치!' 유형에 매달리면 사람들이 찾을 것입니다!
내가 본 확장 방법의 두 가지 추가 이점 :
- 유창한 인터페이스는 확장 메서드의 정적 클래스로 캡슐화 될 수 있으므로 핵심 클래스와 유창한 확장 사이의 문제를 분리 할 수 있습니다. 나는 더 큰 유지 보수를 달성하는 것을 보았다
- 확장 메서드는 인터페이스에서 중단 될 수 있으므로 컨트랙트 (인터페이스를 통해) 및 연관된 일련의 인터페이스 기반 동작 (확장 메서드를 통해)을 지정할 수 있으며 다시 우려 사항을 분리 할 수 있습니다.
확장 메서드에 대한 가장 좋은 용도 중 일부는 다음과 같은 기능입니다.
- 타사 개체의 기능을 확장합니다 (상업적이든 회사 내부이든 별도의 그룹에서 관리함). 대부분의 경우
sealed
. - 추상 클래스를 구현할 필요없이 인터페이스에 대한 기본 기능 생성
예를 들어, IEnumerable<T>
. 확장 메서드가 풍부하지만 일반적인 ForEach 메서드를 구현하지 않은 것이 귀찮습니다. 그래서 나는 내 자신을 만들었습니다.
public void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach ( var o in enumerable )
{
action(o);
}
}
Voila, IEnumerable<T>
구현 유형에 관계없이 내 모든 객체, 내가 작성했는지 여부에 관계없이 이제 ForEach
내 코드에 적절한 "using"문을 추가하여 메서드를 갖게 되었습니다.
확장 메서드를 사용하는 가장 큰 이유 중 하나는 LINQ입니다. 확장 메서드가 없으면 LINQ에서 할 수있는 많은 작업이 매우 어려울 것입니다. Where (), Contains (), Select 확장 메서드는 구조를 변경하지 않고 기존 유형에 더 많은 기능이 추가됨을 의미합니다.
확장 방법 의 장점 에 대한 많은 답변이 있습니다 . 단점을 해결하는 방법은 어떻습니까?
가장 큰 단점은 동일한 컨텍스트에서 동일한 서명을 가진 일반 메서드와 확장 메서드가있는 경우 컴파일러 오류나 경고가 없다는 것입니다.
특정 클래스에 적용되는 확장 메서드를 생성한다고 가정합니다. 그런 다음 나중에 누군가 해당 클래스 자체에 동일한 서명을 가진 메서드를 만듭니다.
코드가 컴파일되고 런타임 오류가 발생하지 않을 수도 있습니다. 그러나 더 이상 이전과 동일한 코드를 실행하지 않습니다.
CodeBetter에서 Greg Young이 시연 한 유창한 인터페이스 및 컨텍스트 민감도
Extension 메서드에 대한 개인적인 주장은 OOP 설계에 매우 적합하다는 것입니다. 간단한 방법을 고려하십시오.
bool empty = String.IsNullOrEmpty (myString)
비교해서
bool empty = myString.IsNullOrEmpty ();
확장 메서드를 통해 수행 할 수있는 작업에 대한 많은 답변이 있습니다.
내 짧은 대답은-그들은 공장에 대한 필요성을 거의 제거합니다.
나는 그것들이 새로운 개념이 아니라는 점을 지적 할 것이며 이들의 가장 큰 검증 중 하나는 Objective-C ( 범주 ) 의 킬러 기능이라는 것 입니다. NeXT는 NSA와 월스트리트 금융 모델러를 주요 사용자로 사용하여 프레임 워크 기반 개발에 많은 유연성을 추가합니다.
REALbasic은 또한 그것들을 extends 메소드 로 구현하고 개발을 단순화하는 유사한 용도로 사용되었습니다.
확장 메서드의 중요한 이유로 향상된 코드 가독성을 언급하는 다른 답변을 지원하고 싶습니다. 이 두 가지 측면, 즉 메서드 체인과 중첩 된 메서드 호출, 그리고 의미없는 정적 클래스 이름이있는 LINQ 쿼리의 복잡함으로이를 설명하겠습니다.
이 LINQ 쿼리를 예로 들어 보겠습니다.
numbers.Where(x => x > 0).Select(x => -x)
Where
및 둘 다 Select
정적 클래스에 정의 된 확장 메서드 Enumerable
입니다. 따라서 확장 메서드가 존재하지 않고 이것이 일반적인 정적 메서드라면 코드의 마지막 줄은 본질적으로 다음과 같아야합니다.
Enumerable.Select(Enumerable.Where(numbers, x => x > 0), x => -x)
그 쿼리가 방금 얼마나 더 나빠 졌는지 확인하십시오.
둘째, 이제 고유 한 쿼리 연산자를 도입하려는 경우 프레임 워크에 있고 해당 클래스를 제어 할 수 없기 Enumerable
때문에 다른 모든 표준 쿼리 연산자처럼 정적 클래스 내에서 정의 할 방법이 당연히 없습니다 Enumerable
. 따라서 확장 메서드를 포함하는 고유 한 정적 클래스를 정의해야합니다. 그런 다음 다음과 같은 쿼리를 얻을 수 있습니다.
Enumerable.Select(MyEnumerableExtensions.RemoveNegativeNumbers(numbers), x => -x)
// ^^^^^^^^^^^^^^^^^^^^^^
// different class name that has zero informational value
// and, as with 'Enumerable.xxxxxx', only obstructs the
// query's actual meaning.
(확장) 메서드를 클래스에 직접 추가 할 수 있다는 것은 사실입니다. 그러나 모든 수업이 당신에 의해 작성되는 것은 아닙니다. 핵심 라이브러리 또는 타사 라이브러리의 클래스는 종종 닫히고 확장 메서드 없이는 구문 적 설탕을 얻을 수 없습니다. 그러나 확장 메서드는 예를 들어 (정적) 독립형 메서드와 같습니다. C ++
확장 메서드는 클래스와 클래스 종속성을 깨끗하게 유지하는데도 도움이됩니다. 예를 들어 Foo가 사용되는 모든 곳에서 Foo 클래스에 대한 Bar () 메서드가 필요할 수 있습니다. 그러나 다른 어셈블리에서 해당 어셈블리에 대해서만 .ToXml () 메서드가 필요할 수 있습니다. 이 경우 원본 어셈블리가 아닌 해당 어셈블리에 필요한 System.Xml 및 / 또는 System.Xml.Linq 종속성을 추가 할 수 있습니다.
이점 : 정의하는 클래스 어셈블리의 종속성이 필수 사항으로 만 줄어들고 다른 소비 어셈블리는 ToXml () 메서드를 사용하지 못합니다. 자세한 내용은 이 PDC 프레젠테이션 을 참조하십시오.
확장 메서드는 실제로 Martin Fowler의 책 (메서드 서명까지) 의 "Introduce Foreign Method" 리팩터링 의 .NET 통합입니다 . 기본적으로 동일한 이점과 함정이 있습니다. 이 리팩터링에 대한 섹션에서 그는 메서드를 실제로 소유해야하는 클래스를 수정할 수없는 경우에 대한 해결 방법이라고 말합니다.
나는 주로 확장 방법이 무료 기능을 허용하지 않아야한다는 인정으로 봅니다.
C ++ 커뮤니티에서는 멤버보다 무료 비 멤버 함수를 선호하는 것이 좋은 OOP 관행으로 간주되는 경우가 많습니다. 이러한 함수는 필요하지 않은 개인 멤버에 대한 액세스 권한을 얻음으로써 캡슐화를 깨지 않기 때문입니다. 확장 방법은 동일한 것을 달성하는 원형 교차로처럼 보입니다. 즉, private 멤버에 액세스 할 수없는 정적 함수에 대한 더 깨끗한 구문입니다.
확장 방법은 구문 설탕에 지나지 않지만 사용하는 데 아무런 해가 없습니다.
- 추악한 유틸리티 함수를 호출하는 대신 객체 자체에 대한 Intellisense
- 변환 함수의 경우 "XToY (X x)"를 "ToY (this X x)"로 변경하면 추악한 XToY (x) 대신 예쁜 x.ToY ()가 생성됩니다.
- 제어 할 수없는 클래스 확장
- 클래스 자체에 메서드를 추가하는 것이 바람직하지 않은 경우 클래스의 기능을 확장합니다. 예를 들어, 비즈니스 객체를 단순하고 논리가없는 상태로 유지하고 확장 메서드에서 추악한 종속성이있는 특정 비즈니스 논리를 추가 할 수 있습니다.
객체 모델 클래스를 재사용하는 데 사용합니다. 데이터베이스에있는 개체를 나타내는 클래스가 많이 있습니다. 이러한 클래스는 클라이언트 측에서만 객체를 표시하는 데 사용되므로 기본 용도는 속성에 액세스합니다.
public class Stock {
public Code { get; private set; }
public Name { get; private set; }
}
이러한 사용 패턴 때문에 이러한 클래스에 비즈니스 논리 메서드를 포함하고 싶지 않으므로 모든 비즈니스 논리를 확장 메서드로 만듭니다.
public static class StockExtender {
public static List <Quote> GetQuotesByDate(this Stock s, DateTime date)
{...}
}
이렇게하면 불필요한 코드로 클라이언트 측에 과부하를주지 않고 비즈니스 로직 처리 및 사용자 인터페이스 표시에 동일한 클래스를 사용할 수 있습니다.
One interesting thing about this solution it's that my object model classes are dynamic generated using Mono.Cecil, so it would be very difficult to add business logic methods even if I wanted. I have a compiler that reads XML definition files and generate these stubs classes representing some object I have in the database. The only approach in this case is to extend them.
I agree that extension methods increases readability of code, but it's really nothing else than static helper methods.
IMO using extension methods for adding behaviour to your classes can be:
Confusing: Programmers might believe that methods are a part of the extended type, thus not understanding why the methods are gone when the extension-namespace isn't imported.
An antipattern: You decide to add behaviour to types in your framework using extension methods, then shipping them off to some person which into unit testing. Now he's stuck with a framework containing a bunch of methods he can't fake.
It allows C# to better support dynamic languages, LINQ and a dozen other things. Check out Scott Guthrie's article.
In my last project, I used extension method to attach Validate() methods to business objects. I justified this because the business objects where serializable data transfer objects and will be used in diffrent domains as they where general ecommerce entities such as product, customer, merchant etc. Well in diffrent domains the business rules may be diffrent as well so I encapsulated my late bound validation logic in a Validate method attahced to the base class of my data transfer objects. Hope this makes sense :)
One case where extension methods were quite useful was in a client-application that uses ASMX web services. Due to the serialization, the return types of web methods do not contain any methods (only the public properties of these types are available on the client).
Extension methods allowed use to add functionality (on the client-side) to the types returned by web methods without having to create yet another object model or numerous wrapper classes on the client-side.
Also remember that extension methods were added as a way to help Linq query to be more readable, when used in their C# style.
These 2 affectations are absolutely equivalent, yet the first is far more readable (and the gap in readibility would of course increase with more methods chained).
int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last();
int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));
Note that the fully qualified syntax should even be :
int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>();
int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));
By chance, the type parameters of Where
and Last
don't need to be explicitely mentioned as they can be infered thanks to the presence of the first parameter of these two methods (the parameter which is introduced by the keyword this
and make them extension methods).
This point is obviously an advantage (among others) of the extension methods, and you can take benefit from it in every similar scenario where method chaining is involved.
Especially, it is the more elegant and convincing way I found to have a base class method invokable by any subclass and returning a strongly typed reference to this subclass (with the subclass type).
Example (ok, this scenario is totally cheesy) : after a good night, an animal opens the eyes then gives a cry; every animal opens the eyes the same way, whereas a dog barks and a duck kwaks.
public abstract class Animal
{
//some code common to all animals
}
public static class AnimalExtension
{
public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
{
//Some code to flutter one's eyelashes and then open wide
return animal; //returning a self reference to allow method chaining
}
}
public class Dog : Animal
{
public void Bark() { /* ... */ }
}
public class Duck : Animal
{
public void Kwak() { /* ... */ }
}
class Program
{
static void Main(string[] args)
{
Dog Goofy = new Dog();
Duck Donald = new Duck();
Goofy.OpenTheEyes().Bark(); //*1
Donald.OpenTheEyes().Kwak(); //*2
}
}
Conceptually OpenTheEyes
should be an Animal
method, but it would then return an instance of the abstract class Animal
, which doesn't know specific subclass methods like Bark
or Duck
or whatever. The 2 lines commented as *1 and *2 would then raise a compile error.
But thanks to the extension methods, we can have kind of a "base method which knows the subclass type on which it is called".
Note that a simple generic method could have done the job, but in a far more awkward way :
public abstract class Animal
{
//some code common to all animals
public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
{
//Some code to flutter one's eyelashes and then open wide
return (TAnimal)this; //returning a self reference to allow method chaining
}
}
This time, no parameter and thus no possible return type inference. The call can be nothing other than :
Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();
... which can weigh the code a lot if more chaining is involved (especially knowing that the type parameter will always be <Dog>
on Goofy's line and <Duck>
on Donald's one...)
I have only one word to tell about it: MAINTAINABILITY this is the key for extension methods use
I think extension methods help to write code that is clearer.
Instead of putting a new method inside your class, as your friend suggested, you put it in the ExtensionMethods namespace. In this way you maintain a logical sense of order to your class. Methods that don't really directly deal with your class won't be cluttering it up.
I feel extension methods make your code clearer and more appropriately organized.
It allows your editor/IDE do auto-complete suggestion smart.
I love them for building html. Frequently there are sections that are used repeatedly, or generated recursively where a function is useful but would otherwise break the flow of the program.
HTML_Out.Append("<ul>");
foreach (var i in items)
if (i.Description != "")
{
HTML_Out.Append("<li>")
.AppendAnchor(new string[]{ urlRoot, i.Description_Norm }, i.Description)
.Append("<div>")
.AppendImage(iconDir, i.Icon, i.Description)
.Append(i.Categories.ToHTML(i.Description_Norm, urlRoot)).Append("</div></li>");
}
return HTML_Out.Append("</ul>").ToString();
There are also situations where an object needs custom logic to be prepared for HTML output- extension methods let you add this functionality without mixing presentation and logic within the class.
I've found extension methods are useful to match nested generic arguments.
That sounds a bit wierd - but say we have a generic class MyGenericClass<TList>
, and we know that TList itself is generic (e.g. a List<T>
), I don't think that there's a way to dig out that nested 'T' from the List without either extension methods or static helper methods. If we only have static helper methods at our disposal, it's (a) ugly, and (b) will force us to move functionality that belongs in the class to an external location.
e.g. to retrieve the types in a tuple and convert them into a method signature we can use extension methods:
public class Tuple { }
public class Tuple<T0> : Tuple { }
public class Tuple<T0, T1> : Tuple<T0> { }
public class Caller<TTuple> where TTuple : Tuple { /* ... */ }
public static class CallerExtensions
{
public static void Call<T0>(this Caller<Tuple<T0>> caller, T0 p0) { /* ... */ }
public static void Call<T0, T1>(this Caller<Tuple<T0, T1>> caller, T0 p0, T1 p1) { /* ... */ }
}
new Caller<Tuple<int>>().Call(10);
new Caller<Tuple<string, int>>().Call("Hello", 10);
That said, I'm not sure where the dividing line should be - when should a method be an extension method, and when should it be a static helper method? Any thoughts?
Extension methods can be used to create a kind of mixin in C#.
This, in turn, provides better separation of concerns for orthogonal concepts. Take a look at this answer as an example.
This can also be used to enable roles in C#, a concept central to the DCI architecture.
I have input zones on my screen, and all must implement a standard behavior whatever their exact types are (textboxes, checkboxes, etc.). They cannot inherit a common base class as each type of input zone already derives from a specific class (TextInputBox, etc.)
Maybe by going up in the inheritance hierachy I could find a common ancestor like say WebControl, but I didn't develop the framework class WebControl and it doesn't expose what I need.
With the extension method, I can :
1) extend the WebControl class, and then obtain my unified standard behavior on all my input classes
2) alternatively make all my classes derive from an interface, say IInputZone, and extend this interface with methods. I will now be able to call extensions methods related to the interface on all my input zones. I thus achieved a kind of multiple inheritance since my input zones already derived from multiple base classes.
There are so many great examples of extension methods..especially on IEnumerables as posted above.
e.g. if I have an IEnumerable<myObject>
I can create and extension method for IEnumerable<myObject>
mylist List<myObject>;
...create the list
mylist.DisplayInMyWay();
Without Extension Methods would have to call:
myDisplayMethod(myOldArray); // can create more nexted brackets.
another great example is creating a Circular Linked List in a flash!
I can' take credit for it!
circlular linked list using extension Methods
Now combine these and using extension Methods code reads as follows.
myNode.NextOrFirst().DisplayInMyWay();
rather than
DisplayInMyWay(NextOrFirst(myNode)).
using Extension Methods It is neater and easier to read and more object orientated. also very close to :
myNode.Next.DoSomething()
Show that to your collegue! :)
참고URL : https://stackoverflow.com/questions/487904/what-advantages-of-extension-methods-have-you-found
'developer tip' 카테고리의 다른 글
Gradle 인수에 대한 compile () 메서드를 찾을 수 없습니다. (0) | 2020.09.20 |
---|---|
Django, 사용자 지정 500/404 오류 페이지 만들기 (0) | 2020.09.20 |
<0xEF, 0xBB, 0xBF> 문자가 파일에 표시됩니다. (0) | 2020.09.20 |
파일 시스템에서 클래스를 이동 한 후 "XXX 클래스는 유효한 엔티티 또는 매핑 된 수퍼 클래스가 아닙니다." (0) | 2020.09.20 |
내부 서버 오류-htaccess (0) | 2020.09.20 |