방프리

24.01.01 Chapter2. API 설계 (Item 25) 본문

C#/More Effective C#

24.01.01 Chapter2. API 설계 (Item 25)

방프리 2024. 1. 1. 14:48

Item 25 : 배열 매개변수에는 params 배열만 사용해야 한다

 

배열은 반공변을 지원하지 않는다. 그렇기 때문에 배열형태의 매개변수를 받을 수 있는 것에 제한이 크다.
그럴 땐  IEnumerable<T> 형태로 사용하는 것이 좋다.

class B
{
    public static B Factory() => new B();
    
    public virtual void WriteType() => WriteLine("B");
}

class D1 : B
{
    public static new B Factory() => new D1();
    
    public override void WriteType() => WriteLine("D1");
}

class D2 : B
{
    public static new B Factory() => new D2();
    
    public override void WriteType() => WriteLine("D2");
}

B[] storage = new D1[10];

//모두 에러
FillArray(storage, () => B.Factory());
FillArray(storage, () => D1.Factory());
FillArray(storage, () => D2.Factory());

하지만 IEnumerable<T>는 내부 시퀸스에 있는 데이터를 수정하진 못한다. 이럴 땐 시퀸스를 인수로 받은 후 수정된 시퀸스를 반환하면 된다.

 static IEnumerable<T> FillArray<T>(IEnumerable<T> storage, Func<T> factory)
 {
     var uniqueVals = new HashSet<T>();
     foreach (var element in storage) 
     {
         if (uniqueVals.Contains(element) == false)
         {
             uniqueVals.Add(factory());
             yield return element;
         }
     }
 }

 static void Main()
 {
     B[] storage = new D1[10];
     FillArray(storage, () => B.Factory());
     FillArray(storage, () => D1.Factory());
     FillArray(storage, () => D2.Factory());
 }

순수 배열을 매개변수로 전달할 때 두 가지 문제를 야기한다. 첫 번째는 배열은 공변을 지원하므로 런타임 오류를 
발생시킬 수 있다. 두 번째는 배열은 요소를 간접적으로 참조하기 때문에 매개변수로 전달받은 배열은 변경될 수 있다.
하지만 그것이 정확한지는 판단할 수는 없다 그렇기에 가변적인 배열이라면 params 배열을 사용하는 것이 
좀 더 안정적이다.

Comments