C# 10 부터 인터페이스에 메소드나 속성에 ‘static abstract’ 키워드를 적용하게 되면 인터페이스로 정적 오퍼레이터 메소드에 접근할 수 있게 되어 제네릭을 통한 연산이 가능하게 됩니다.
TValue Sum<TValue>(TValue a, TValue b) where TValue: INumber<TValue> => a + b;
제네릭 연산 말고 어떤 곳에서 또 유용하게 사용 가능할까요?
인터페이스에 static abstract
키워드로 메소드나 속성을 만들었다면, 인터페이스를 구현하는 클래스에서 반드시 해당 메소드나 속성을 구현해줘야 합니다.
interface ICreatable
{
static abstract Driver Create(string driverName);
}
interface IDriver : ICreatable
{
string Name { get; }
}
abstract class Driver : IDriver
{
private static readonly Driver Empty = new EmptyDriver();
public abstract string Name { get; }
public static Driver Create(string driverName) => driverName switch
{
"A" => new ADriver(),
"B" => new BDriver(),
_ => Empty
};
}
class EmptyDriver : Driver
{
public override string Name => "Empty";
}
class ADriver : Driver
{
public override string Name => "A";
}
class BDriver : Driver
{
public override string Name => "B";
}
사용은,
var a = Driver.Create("A");
var b = Driver.Create("B");
var c = Driver.Create("C");
Console.WriteLine(a.Name);
Console.WriteLine(b.Name);
Console.WriteLine(c.Name);
여기서 static abstract
는 abstract
가 들어갔기 때문에 추상화가 가능한 것 처럼 보이지만, 그렇지 않습니다. 여기서 abstract
의 의미는 “구현해야 하는” 정도로 해석하는게 맞습니다. 실제로 다음처럼 Driver의 Create()
에 abstract
를 넣으면 하면 오류가 발생합니다.
public static abstract Driver Create(string driverName); // 오류 발생
// CS0112: 'abstract' 정적 멤버는 override, virtual 또는 abstract로 표시할 수 없습니다.
흠, 기능적으로는 이 메소드를 최종 구현하는 자식 클래스에서 static override Driver Create()
로 구현해줘도 혼란이 없을 것 같은데, 일단은 이 방식을 막았습니다. abstract - override 키워드가 주는 다형성
의 느낌때문인것 같은데, 기능적으로는 문제될게 없기 때문에 차후에 추가되기를 기대해 봅니다.
다음으로 인터페이스 인스턴스로는 Create()
메소드에 접근할 수 없습니다.
var ia = a as IDriver;
Console.WriteLine(ia.Name);
// ia.Create("D"); // 인터페이스형의 인스턴스로는 접근 안됨
이것은 어찌보면 당연한게, static abstract
로 정의된 메소드에 접근하기 위해 개체지향의 다형성
(vtable 접근 방식)으로 호출하는게 아니기 때문입니다.
하지만 다음은 허용합니다.
var a2 = DriverExtention.Create(a);
static class DriverExtention
{
public static Driver Create<T>(T otherDriver) where T : IDriver => T.Create(otherDriver.Name);
}
이것이 가능한 이유는 제네릭 T가 컴파일 타임 때 결정되기 때문입니다.