안녕하세요.
여러분들은 target-typed new expressions를 많이 사용하시나요?
저는 위 표현을 알고나서부터 var 대신 주로 사용하고 있습니다.
최근 delegate chain 샘플 코드를 작성하다가 컴파일이 되지 않는 상황을 겪어 공유하고자 합니다.
환경은 visual studio 2022, .NET6 입니다.
컴파일 하기 전까지 어디 구문에서 에러가 발생했는지 표시가 안되고 따로 문제가 있는 부분이 없는 코드인 것 같지만 오류 CS7038 모듈 'ConsoleApp'을(를) 내보내지 못했습니다. 오류의 특정 원인을 확인할 수 없습니다. 가 발생하면서 정확한 원인을 파악할 수 없더라고요.
sharplab에서도 같은 에러가 발생합니다. ![]()
그나마 문제가 될 것 같은 부분이 12번 라인이라 이것저것 테스트해본 결과 += 연산일 때 target-typed new expressions가 동작을 안하는 것 같습니다.
void FooOne()
{
Console.WriteLine("Foo One!!");
}
void FooTwo()
{
Console.WriteLine("Foo Two!!");
}
// success
// FooDelegate fooDelegate = FooOne;
// fooDelegate += FooTwo;
// success
// FooDelegate fooDelegate = new FooDelegate(FooOne);
// fooDelegate += new FooDelegate(FooTwo);
// error
FooDelegate fooDelegate = new (FooOne);
fooDelegate += new (FooTwo);
fooDelegate.Invoke();
delegate void FooDelegate();
컴파일이 성공하는 두 표현을 sharplap에서 컴파일된 결과를 보면
public void Print()
{
FooDelegate a = new FooDelegate(FooOne);
a = (FooDelegate)Delegate.Combine(a, new FooDelegate(FooTwo));
FooDelegate a2 = new FooDelegate(FooOne);
a2 = (FooDelegate)Delegate.Combine(a2, new FooDelegate(FooTwo));
}
+= 연산이 Delegate.Combine으로 치환되는 모습을 확인해 볼 수 있었습니다.
하지만 target-typed new expressions를 사용하면 안되는 것으로 보아 Delegate.Combine 메서드의 매개변수가 Delegate 추상타입이라 타입을 유추할 수 없어서 그런가 싶기도 하고… 정확한 원인을 몰라서 roslyn에 github issue로 등록을 했습니다.
관련 개발자분들이 댓글을 달아주셨는데 target-typed new expressions은 대입 연산자(=)에서만 사용이 가능하다고 하지만 event는 +=가 처리가 된다고 하네요.
추가적으로 switch문을 사용하면 에러가 발생하지 않는다고 하는데… 확인해보니 정말 에러가 발생하지는 않습니다.
- event 사용
Foo foo = new();
foo.FooEvent += FooOne;
foo.FooEvent += new(FooTwo); // 표현 가능!
foo.Print();
void FooOne()
{
Console.WriteLine("FooOne!");
}
void FooTwo()
{
Console.WriteLine("FooTwo!");
}
class Foo
{
public delegate void FooDelegate();
public event FooDelegate FooEvent;
public void Print() => FooEvent.Invoke();
}
---> sharplab 컴파일
Foo foo = new Foo();
foo.FooEvent += new Foo.FooDelegate(FooOne);
foo.FooEvent += new Foo.FooDelegate(FooTwo);
- switch 식 사용
void FooOne()
{
Console.WriteLine("Foo One!!");
}
void FooTwo()
{
Console.WriteLine("Foo Two!!");
}
string type = "two";
FooDelegate fooDelegate = new(FooOne);
fooDelegate += type switch // 표현 가능!
{
"one" => new(FooOne),
"two" => new(FooTwo),
_ => throw new ArgumentException(),
};
fooDelegate.Invoke();
delegate void FooDelegate();
---> sharplab 컴파일
string text = "two";
FooDelegate fooDelegate = new FooDelegate(FooOne);
FooDelegate a = fooDelegate;
FooDelegate b;
if (!(text == "one"))
{
if (!(text == "two"))
{
throw new ArgumentException();
}
b = new FooDelegate(FooTwo);
}
else
{
b = new FooDelegate(FooOne);
}
fooDelegate = (FooDelegate)Delegate.Combine(a, b);
fooDelegate();
event가 이미 처리되고 있듯이 delegate도 컴파일이 가능해야 될 것 같다곤 하는데, 위 이슈가 처리가 될지는 모르겠네요.
현재 상황으로서는 delegate chain 사용 시 target-typed new expressions 표현에 주의가 필요해 보입니다.
