C #에서 확장 메서드를 좋아하지만 콘솔과 같은 정적 클래스에 확장 메서드를 추가하는 데 성공하지 못했습니다.
예를 들어 콘솔에 ‘WriteBlueLine’이라는 확장을 추가하고 싶다면 다음을 수행하십시오.
Console.WriteBlueLine("This text is blue");
콘솔을 ‘this’매개 변수로 사용하여 로컬 공개 정적 메소드를 추가하여 시도했지만 주사위는 없습니다!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
이것은 콘솔에 ‘WriteBlueLine’메서드를 추가하지 않았습니다 … 잘못하고 있습니까? 아니면 불가능을 요구합니까?
답변
아니요. 확장 메서드에는 개체의 인스턴스 변수 (값)가 필요합니다. 그러나 ConfigurationManager
인터페이스 주위에 정적 랩퍼를 작성할 수 있습니다 . 랩퍼를 구현하는 경우 메소드를 직접 추가 할 수 있으므로 확장 메소드가 필요하지 않습니다.
public static class ConfigurationManagerWrapper
{
public static ConfigurationSection GetSection( string name )
{
return ConfigurationManager.GetSection( name );
}
.....
public static ConfigurationSection GetWidgetSection()
{
return GetSection( "widgets" );
}
}
답변
C #에서 클래스에 정적 확장을 추가 할 수 있습니까? 아니요, 그러나 당신은 이것을 할 수 있습니다 :
public static class Extensions
{
public static T Create<T>(this T @this)
where T : class, new()
{
return Utility<T>.Create();
}
}
public static class Utility<T>
where T : class, new()
{
static Utility()
{
Create = Expression.Lambda<Func<T>>(Expression.New(typeof(T).GetConstructor(Type.EmptyTypes))).Compile();
}
public static Func<T> Create { get; private set; }
}
작동 방식은 다음과 같습니다. 정적 확장 메서드를 기술적으로 작성할 수는 없지만이 코드는 확장 메서드의 허점을 악용합니다. 허점은 null 예외를 얻지 않고 null 객체에서 확장 메서드를 호출 할 수 있다는 것입니다 (@this를 통해 아무것도 액세스하지 않는 한).
이것을 사용하는 방법은 다음과 같습니다.
var ds1 = (null as DataSet).Create(); // as oppose to DataSet.Create()
// or
DataSet ds2 = null;
ds2 = ds2.Create();
// using some of the techniques above you could have this:
(null as Console).WriteBlueLine(...); // as oppose to Console.WriteBlueLine(...)
이제 기본 생성자를 예제로 호출하는 이유는 무엇이며 왜 Expression 가비지를 모두 수행하지 않고 첫 번째 코드 스 니펫에서 새 T ()를 반환하지 않습니까? 오늘은 운이 좋은 날인데 2fer를 얻었 기 때문입니다. 고급 .NET 개발자가 알고 있듯이 새 T ()는 리플렉션을 사용하여 기본 생성자를 가져와 호출하기 전에 System.Activator에 대한 호출을 생성하므로 속도가 느립니다. 젠장, 마이크로 소프트! 그러나 내 코드는 객체의 기본 생성자를 직접 호출합니다.
정적 확장은 이것보다 낫지 만 절박한 시간에는 필사적 인 조치가 필요합니다.
답변
불가능합니다.
그리고 네, MS는 여기서 실수를 한 것 같습니다.
그들의 결정은 의미가 없으며 프로그래머가 (위에서 설명한 것처럼) 무의미한 래퍼 클래스를 작성하도록 강요합니다.
다음은 좋은 예입니다. 정적 MS 단위 테스트 클래스를 확장하려고 시도합니다. Assert : 1 개 이상의 Assert 메소드가 필요 AreEqual(x1,x2)
합니다.
이를 수행 할 수있는 유일한 방법은 다른 클래스를 가리 키거나 약 100 개의 다른 Assert 메소드를 래퍼로 작성하는 것입니다. 왜!?
인스턴스 확장을 허용하기로 결정한 경우 정적 확장을 허용하지 않는 논리적 인 이유가 없습니다. 인스턴스를 확장 할 수 있으면 라이브러리 섹션화에 대한 논쟁은 일어나지 않습니다.
답변
OP와 같은 질문에 대한 답을 찾으려고 노력 하면서이 스레드를 우연히 발견했습니다. 원하는 답변을 찾지 못했지만 결국이 작업을 수행했습니다.
public static class MyConsole
{
public static void WriteLine(this ConsoleColor Color, string Text)
{
Console.ForegroundColor = Color;
Console.WriteLine(Text);
}
}
그리고 나는 이것을 다음과 같이 사용합니다 :
ConsoleColor.Cyan.WriteLine("voilà");
답변
어쩌면 사용자 정의 네임 스페이스와 동일한 클래스 이름으로 정적 클래스를 추가 할 수 있습니다.
using CLRConsole = System.Console;
namespace ExtensionMethodsDemo
{
public static class Console
{
public static void WriteLine(string value)
{
CLRConsole.WriteLine(value);
}
public static void WriteBlueLine(string value)
{
System.ConsoleColor currentColor = CLRConsole.ForegroundColor;
CLRConsole.ForegroundColor = System.ConsoleColor.Blue;
CLRConsole.WriteLine(value);
CLRConsole.ForegroundColor = currentColor;
}
public static System.ConsoleKeyInfo ReadKey(bool intercept)
{
return CLRConsole.ReadKey(intercept);
}
}
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteBlueLine("This text is blue");
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
}
}
답변
C # 7부터는 지원되지 않습니다. 그러나 C # 8 과 같은 것을 통합하고 지원할 가치가있는 제안 에 대한 논의 가 있습니다 .
답변
아니. 확장 메소드 정의에는 확장하려는 유형의 인스턴스가 필요합니다. 불행한; 왜 필요한지 모르겠습니다 …