interface default κ΅¬ν˜„

ν•΄λ‹Ή κ²Œμ‹œκΈ€μ„ 보며, κ°‘μžκΈ° κΆκΈˆν•œκ²Œ μƒκ²¨μ„œ μ£Όλ‹ˆμ–΄ 개발자인 μ €μ—κ²ŒλŠ” μΆ”ν›„ μŠ€νŽ™μ„ 잘λͺ»μ΄ν•΄ν•  것 κ°™μ•„μ„œ 이것저것 μ‹€ν—˜ν•΄λ³΄κ³  κ³΅μœ λ“œλ¦¬λ €ν•©λ‹ˆλ‹€.

μ œκ°€ 처음 ν•΄λ‹Ή κΈ°λŠ₯을 처음 μ ‘ν•˜κ³  λ“  생각은 Diamond Problem을 λ§‰κΈ°μœ„ν•΄μ„œ class 닀쀑 상속을 λ§‰μ€κ²Œ μ•„λ‹ˆμ—ˆλ‚˜?

Interface λ₯Ό 닀쀑 상속 λ°›κ³  default κ΅¬ν˜„μ΄ κ°™λ‹€λ©΄? 무엇을 ν˜ΈμΆœν•˜μ§€? λΌλŠ” μƒκ°μ΄λ“€μ–΄μ„œ
μ•„λž˜μ™€ 같은 μ½”λ“œλ₯Ό μž‘μ„±ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

public interface IFooA
{
    void Print()
    {
        Console.WriteLine($"{nameof(IFooA)} κΈ°λ³Έ κ΅¬ν˜„");
    }
}

public interface IFooB
{
    void Print()
    {
        Console.WriteLine($"{nameof(IFooB)} κΈ°λ³Έ κ΅¬ν˜„");
    }
}

public class FooA : IFooA
{
    
}

public class Foo : IFooA, IFooB
{
}

var fooA = new FooA();
fooA.Print(); // 컴파일 μ—λŸ¬

var a = fooA as IFooA;
a?.Print(); // 좜λ ₯: IFooA κΈ°λ³Έ κ΅¬ν˜„

var foo = new Foo();
foo.Print(); // 컴파일 μ—λŸ¬

Safely update interfaces using default interface methods - C# | Microsoft Learn

However, the SampleCustomer class doesn’t inherit members from its interfaces.

μœ„ 링크처럼 interfaceμ—μ„œ 멀버λ₯Ό μƒμ†ν•˜μ§€ μ•ŠλŠ” λ‹€λŠ” κΈ°λ³Έ κ·œμΉ™μ€ μœ μ§€ν•œλ‹€κ³  ν•©λ‹ˆλ‹€.

μœ„μ˜ 정보λ₯Ό μ°Ύλ‹€λ³΄λ‹ˆ Redditμ—μ„œ λͺ»λ³Όκ±Έ 또 λ°œκ²¬ν•˜κ³  λ§μ•˜μŠ΅λ‹ˆλ‹€.

In java, scala, and kotlin, they behave as expected, as the implementing class inherit the default methods, but in C#, β€œA class does not inherit members from its interfaces” (from the doc itself).

public interface IFooA {
    default void print() {
        System.out.println("FooA");
    }
}

public class Foo implements IFooA {
}

public static void main(String[] args) {
    var foo = new Foo();
    foo.print(); // 좜λ ₯: "FooA";
}

(μœ„μ˜ μ½”λ“œλŠ” JAVA μž…λ‹ˆλ‹€)
μ—‡! 그러면 IFooBλ₯Ό μΆ”κ°€ν•˜λ©΄ μ–΄λ–»κ²Œλ κΉŒμš”?

κ·Έλž˜λ„ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜λΌκ³  컴파일 μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€κ³  μžˆλ„€μš”.

https://www.reddit.com/r/csharp/comments/120kr4p/default_interface_methods_and_inheritance/

reddit에 ν•΄λ‹Ή 닡변을 μžμ„Ένžˆ 달아주신뢄이 μžˆμ–΄μ„œ λŒ€μ²΄ν•©λ‹ˆλ‹€!

ν˜Ήμ‹œ 읽기 μ‹«μœΌμ‹ λΆ„μ€ 밑에 μš”μ•½λ³Έμ„ λ΄μ£Όμ‹œλ©΄ 될 것 κ°™μŠ΅λ‹ˆλ‹€!
Reddit에 달린 κΈ€ μš”μ•½λ³Έμ„ λ²ˆμ—­ν•΄μ„œ 달아 λ†“κ² μŠ΅λ‹ˆλ‹€.

μΈν„°νŽ˜μ΄μŠ€λŠ” 본질적으둜 κ΅¬ν˜„μ„ κ°€μ§€μ§€ μ•ŠλŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€.
μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν•œ 번 κ³΅κ°œν•œ 이후에 λ³€κ²½ν•˜λŠ” 것은 ν˜Έν™˜μ„±μ„ κΉ¨λœ¨λ¦¬λŠ” λ³€ν™” μž…λ‹ˆλ‹€.
이런 ν˜Έν™˜μ„± 깨짐은, 아무리 고톡을 쀄이렀 해도 항상 κ³ ν†΅μŠ€λŸ½μŠ΅λ‹ˆλ‹€.

일뢀 μ‚¬λžŒλ“€μ€ μΈν„°νŽ˜μ΄μŠ€μ— λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜λŠ” 것이 곡개 μ΄ν›„μ—λŠ” ν˜Έν™˜μ„±μ„ κΉ¨λœ¨λ¦¬λŠ” λ³€ν™”λΌλŠ” 점을 μ’‹μ•„ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.
C# νŒ€μ€ 이λ₯Ό μ΅œλŒ€ν•œ μ•ˆμ „ν•˜κ²Œ λ§Œλ“€κΈ° μœ„ν•΄ λ…Έλ ₯ν–ˆμŠ΅λ‹ˆλ‹€.
κ·ΈλŸΌμ—λ„ λΆˆκ΅¬ν•˜κ³  ν˜Έν™˜μ„±μ„ κΉ¨λœ¨λ¦¬λŠ” λ³€ν™”λŠ” μ—¬μ „νžˆ κ³ ν†΅μŠ€λŸ½μŠ΅λ‹ˆλ‹€.

C#은 μΌκ΄€λ˜κ²Œ, 클래슀 기반의 virtualκ³Ό abstract λ©”μ„œλ“œλ§Œ λ‹€ν˜•μ„±μ„ κ°€μ§€λ©°, κ·Έ μ™Έμ˜ 기법듀은 κ·Έλ ‡μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

6개의 μ’‹μ•„μš”

λΉ„μŠ·ν•œ 이유둜 저도 μΈν„°νŽ˜μ΄μŠ€ λ³΄λ‹€λŠ” λŒ€λ¦¬μžλ₯Ό 많이 μ‚¬μš©ν•©λ‹ˆλ‹€.

λŒ€λ¦¬μžλŠ” 근본적으둜 ν•˜λ‚˜μ˜ ν–‰μœ„λ§Œ μ •μ˜ν•  수 μžˆλ‹€λŠ” νŠΉμ§• λ•Œλ¬Έμ—, μƒˆλ‘œμš΄ ν–‰μœ„κ°€ ν•„μš”ν•œ μ‹œμ μ— μƒˆλ‘œμš΄ λŒ€λ¦¬μžλ₯Ό μ •μ˜ν•˜λ©΄ λ˜λŠ”λ°, μƒˆλ‘œμš΄ λŒ€λ¦¬μžκ°€ κ³Όκ±° μ½”λ“œμ— λ―ΈμΉ˜λŠ” 영ν–₯이 μ—†μ–΄, 고톡을 κ²ͺ을 ν™•λ₯ λ„ μ œλ‘œμž…λ‹ˆλ‹€. 이에 λ°˜ν•΄, 이미 κ³΅κ°œλ˜μ–΄ κ΅¬ν˜„ ν΄λž˜μŠ€κ°€ μˆ˜μ‹­κ°œμΈ μƒν™©μ—μ„œ μΈν„°νŽ˜μ΄μŠ€μ— λ©”μ„œλ“œ ν•˜λ‚˜ μΆ”κ°€ν•˜λ©΄, 고톡이 μ‹œμž‘λ˜λŠ” 것이죠. ^^

(좔상 클래슀의 virtual 멀버와 μΈν„°νŽ˜μ΄μŠ€μ˜ κΈ°λ³Έ κ΅¬ν˜„μ€ 이런 κ³ ν†΅μ˜ μ™„ν™”μˆ˜λ‹¨μ΄ 될 수 μžˆμ§€λ§Œ, 해결책은 μ•„λ‹™λ‹ˆλ‹€.)

λŒ€λ¦¬μžλŠ” λ‹€λ₯Έ 이점도 λ§Žμ€λ°, μš°μ„  μ½”λ“œλŸ‰μ΄ μ μŠ΅λ‹ˆλ‹€.

public interface IFooA
{
   void Print();
}
class Foo : IFooA
{
   public void Print() // ...
}
class Bar : IFooA
{
   public void Print() // ...
}
public delegate void Print();

public static class Prints 
{
   public Print Foo() => () => { // ... }
   public Print Bar() => () => { // ... }
}

사싀, 예제λ₯Ό λ°”νƒ•μœΌλ‘œ λΉ„κ΅ν•˜λŠλΌ μœ„μ™€ 같은 무쓸λͺ¨ μ½”λ“œλ₯Ό μ μ—ˆμ§€λ§Œ, μ‹€λ¬΄μ—μ„œ μ‚¬μš©λ˜λŠ” λ³΅μž‘ν•œ 도메인 ν”„λ‘œμ„ΈμŠ€λ₯Ό λ‚˜νƒ€λ‚Ό λ•ŒλŠ” ν•œ μΈ΅ 더 κ°•λ ₯ν•©λ‹ˆλ‹€.

public delegate void Print(string message);
public static class Prints 
{
   public Print Stream(Stream stream) => 
      (m) => { // ... };

   public Print Post(HttpClient proxy, string path) =>
      (m) => { // ... };

   public static Print Then(this Print a, Print b) => 
      (m) => { a(m); b(m); };

   public static Print StreamAndPost(Stream stream, HttpClient proxy, string path) =>
      Stream(stream).Then(Post(http, path));
}

이런 νŠΉμ§•μœΌλ‘œ μš”μ¦˜ μœ ν–‰ν•˜λŠ” CQRS λ‹ˆ CQS λ‹ˆ ν•˜λŠ” 것듀과도 μ•„μ£Ό 잘 μ–΄μšΈλ¦¬κ³ , DI 도 λ¬Έμ œκ°€ μ—†μŠ΅λ‹ˆλ‹€.(κ·ΈλŸ¬λ‚˜ DIλŠ” μΆ”μ²œν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.)

μ‚¬μ†Œν•˜κ²ŒλŠ” 집합을 닀루기도 νŽΈν•©λ‹ˆλ‹€.

List<IFooA> _fooAs = [];

public void Remove(IFooA fooA)
{
   if (_fooAs.FirstOrDefault(x => x.Equals(fooA)) is IFooA exist)
   {
      _fooAs.Remove(exist);
   }
}
Print _prints;
public void Remove(Print print) => _prints -= print; // 없어도 μ—λŸ¬ μ—†μŒ.
3개의 μ’‹μ•„μš”