문제

C# 제네릭 이전에는 모든 사람이 IEnumerable을 구현하는 컬렉션 기반을 만들어 비즈니스 개체에 대한 컬렉션을 코딩했습니다.

즉:

public class CollectionBase : IEnumerable

그런 다음 거기에서 비즈니스 개체 컬렉션을 파생시킵니다.

public class BusinessObjectCollection : CollectionBase

이제 일반 목록 클래스를 대신 사용하는 사람이 있나요?나는 두 가지 기술을 절충하여 사용한다는 것을 발견했습니다.

public class BusinessObjectCollection : List<BusinessObject>

나는 단순히 목록을 전달하는 대신 강력한 형식의 이름을 사용하는 것을 좋아하기 때문에 이렇게 합니다.

무엇인가요 당신의 접근하다?

도움이 되었습니까?

해결책

어떤 이유로 데이터 구조를 캡슐화하고 해당 기능의 제한된 하위 집합을 제공해야 하는 경우를 제외하고는 일반적으로 List를 직접 사용하는 진영에 있습니다.이는 주로 캡슐화가 특별히 필요하지 않은 경우 캡슐화를 수행하는 것은 단지 시간 낭비이기 때문입니다.

그러나 C# 3.0의 집계 초기화 기능을 사용하면 사용자 지정 컬렉션 클래스 사용을 권장하는 몇 가지 새로운 상황이 있습니다.

기본적으로 C# 3.0에서는 다음을 구현하는 모든 클래스를 허용합니다. IEnumerable 새로운 집계 이니셜라이저 구문을 사용하는 Add 메서드가 있습니다.예를 들어 Dictionary는 Add(K key, V value) 메서드를 정의하므로 다음 구문을 사용하여 사전을 초기화할 수 있습니다.

var d = new Dictionary<string, int>
{
    {"hello", 0},
    {"the answer to life the universe and everything is:", 42}
};

이 기능의 가장 큰 장점은 인수 개수에 관계없이 add 메서드에서 작동한다는 것입니다.예를 들어 다음 컬렉션이 있다고 가정해 보겠습니다.

class c1 : IEnumerable
{
    void Add(int x1, int x2, int x3)
    {
        //...
    }

    //...
}

다음과 같이 초기화하는 것이 가능할 것입니다:

var x = new c1
{
    {1,2,3},
    {4,5,6}
}

이는 복잡한 개체의 정적 테이블을 생성해야 하는 경우 매우 유용할 수 있습니다.예를 들어 방금 사용하고 있었다면 List<Customer> 그리고 다음과 같이 만들어야 하는 고객 개체의 정적 목록을 만들고 싶었습니다.

var x = new List<Customer>
{
    new Customer("Scott Wisniewski", "555-555-5555", "Seattle", "WA"),
    new Customer("John Doe", "555-555-1234", "Los Angeles", "CA"),
    new Customer("Michael Scott", "555-555-8769", "Scranton PA"),
    new Customer("Ali G", "", "Staines", "UK")
}

그러나 다음과 같이 사용자 정의된 컬렉션을 사용하는 경우:

class CustomerList  : List<Customer>
{
    public void Add(string name, string phoneNumber, string city, string stateOrCountry)
    {
        Add(new Customer(name, phoneNumber, city, stateOrCounter));
    }
}

그런 다음 다음 구문을 사용하여 컬렉션을 초기화할 수 있습니다.

var customers = new CustomerList
{
    {"Scott Wisniewski", "555-555-5555", "Seattle", "WA"},
    {"John Doe", "555-555-1234", "Los Angeles", "CA"},
    {"Michael Scott", "555-555-8769", "Scranton PA"},
    {"Ali G", "", "Staines", "UK"}
}

이는 각 요소의 요소 유형 이름을 다시 입력할 필요가 없기 때문에 입력하기 쉽고 읽기 쉽다는 장점이 있습니다.요소 유형이 길거나 복잡한 경우 이점이 특히 강할 수 있습니다.

즉, 이는 앱에 정의된 정적 데이터 컬렉션이 필요한 경우에만 유용합니다.컴파일러와 같은 일부 유형의 앱은 이를 항상 사용합니다.일반적인 데이터베이스 앱과 같은 다른 앱은 데이터베이스에서 모든 데이터를 로드하기 때문에 그렇지 않습니다.

내 조언은 객체의 정적 컬렉션을 정의해야 하거나 컬렉션 인터페이스를 캡슐화해야 하는 경우 사용자 정의 컬렉션 클래스를 생성하라는 것입니다.그렇지 않으면 그냥 사용할 것입니다 List<T> 곧장.

다른 팁

그것은 추천 공개 API에서는 List<T>를 사용하지 않고 Collection<T>을 사용합니다.

그래도 그것을 상속받는다면 괜찮을 것입니다.

그냥 사용하는 걸 더 좋아해요 List<BusinessObject>.이를 형식 정의하면 코드에 불필요한 상용구가 추가됩니다. List<BusinessObject> 특정 유형입니다. 단순한 유형이 아닙니다. List 개체이므로 여전히 강력한 형식입니다.

더 중요한 것은 무언가를 선언하는 것입니다. List<BusinessObject> 코드를 읽는 모든 사람이 자신이 다루고 있는 유형을 더 쉽게 알 수 있으며, 어떤 유형인지 알아내기 위해 검색할 필요가 없습니다. BusinessObjectCollection 그리고 그것은 단지 목록일 뿐이라는 것을 기억하세요.형식 정의를 통해 모든 사람이 이해하기 위해 따라야 하는 일관된 (재) 명명 규칙을 요구해야 합니다.

유형을 사용하십시오 List<BusinessObject> 그 목록을 선언해야 하는 곳입니다.그러나 목록을 반환하는 곳 BusinessObject, 복귀를 고려해보세요 IEnumerable<T>, IList<T> 또는 ReadOnlyCollection<T> - 즉.클라이언트를 만족시키는 가장 약한 계약을 반환합니다.

목록에 "사용자 정의 코드를 추가"하려는 경우 목록 유형의 코드 확장 메서드를 사용하세요.다시 말하지만, 이러한 메서드를 가능한 가장 약한 계약에 연결하세요.

public static int SomeCount(this IEnumerable<BusinessObject> someList)

물론 확장 메서드를 사용하여 상태를 추가할 수도 없고 추가해서도 안 됩니다. 따라서 새 속성과 그 뒤에 필드를 추가해야 하는 경우 하위 클래스 또는 더 나은 래퍼 클래스를 사용하여 이를 저장하세요.

나는 2가지 옵션을 왔다 갔다 했습니다.

public class BusinessObjectCollection : List<BusinessObject> {}

또는 다음을 수행하는 메서드:

public IEnumerable<BusinessObject> GetBusinessObjects();

첫 번째 접근 방식의 이점은 메서드 서명을 망칠 필요 없이 기본 데이터 저장소를 변경할 수 있다는 것입니다.불행하게도 이전 구현에서 메서드를 제거하는 컬렉션 형식에서 상속하는 경우 코드 전체에서 이러한 상황을 처리해야 합니다.

해당 목적을 위해 자신만의 컬렉션을 만드는 것은 피해야 합니다.리팩토링 중이나 새 기능을 추가할 때 데이터 구조 유형을 몇 번 변경하려는 경우는 매우 일반적입니다.귀하의 접근 방식을 사용하면 BusinessObjectList, BusinessObjectDictionary, BusinessObjectTree 등에 대한 별도의 클래스가 생성됩니다.

클래스 이름이 더 읽기 쉽다는 이유만으로 이 클래스를 만드는 데 아무런 가치가 없다고 생각합니다.예, 꺾쇠 괄호 구문은 다소 보기 흉하지만 C++, C# 및 Java의 표준이므로 이를 사용하는 코드를 작성하지 않더라도 항상 꺾쇠 괄호 구문을 사용하게 될 것입니다.

나는 일반적으로 "가치 추가"가 필요한 경우에만 내 컬렉션 클래스를 파생합니다.예를 들어, 컬렉션 자체에 태그가 붙은 "메타데이터" 속성이 필요한 경우입니다.

나도 조나단 너랑 똑같은 짓을 하고 있어...그냥 상속받아 List<T>.두 가지 장점을 모두 누릴 수 있습니다.하지만 저는 일반적으로 추가할 가치가 있는 경우에만 이 작업을 수행합니다. LoadAll() 방법이든 뭐든.

둘 다 사용할 수 있습니다.게으름에 대한 - 생산성을 의미합니다. - List는 매우 유용한 클래스이며 "포괄적"이며 솔직히 YANGNI 멤버로 가득 차 있습니다.의 합리적인 주장/권고와 결합하여 MSDN 기사 List를 공개 멤버로 노출하는 것에 대해 이미 링크되어 있으므로 "세 번째" 방법을 선호합니다.

개인적으로 나는 데코레이터 패턴을 사용하여 List에서 필요한 것만 노출합니다. 즉:

public OrderItemCollection : IEnumerable<OrderItem> 
{
    private readonly List<OrderItem> _orderItems = new List<OrderItem>();

    void Add(OrderItem item)
    {
         _orderItems.Add(item)
    }

    //implement only the list members, which are required from your domain. 
    //ie. sum items, calculate weight etc...

    private IEnumerator<string> Enumerator() {
        return _orderItems.GetEnumerator();
    }

    public IEnumerator<string> GetEnumerator() {
        return Enumerator();
    }    
}

더 나아가 OrderItemCollection을 IOrderItemCollection으로 추상화하여 나중에 IOrderItemCollection의 구현을 교체할 수 있습니다(Collection과 같은 다른 내부 열거 가능 객체를 사용하거나 키 값 쌍 컬렉션 또는 Set을 사용하는 것이 더 좋을 수도 있습니다). .

저는 거의 모든 시나리오에 일반 목록을 사용합니다.더 이상 파생 컬렉션 사용을 고려하는 유일한 경우는 컬렉션 특정 멤버를 추가하는 경우입니다.그러나 LINQ의 출현으로 인해 그 필요성도 줄어들었습니다.

1개 중 6개, 또 다른 6개

어느 쪽이든 그것은 같은 것입니다.BusinessObjectCollection에 사용자 정의 코드를 추가해야 할 이유가 있는 경우에만 이 작업을 수행합니다.

로드 메소드가 목록을 반환하지 않으면 공통 일반 클래스에 더 많은 코드를 작성하고 제대로 작동하도록 할 수 있습니다.Load 메서드 등이 있습니다.

다른 사람이 지적했듯이 List를 공개적으로 노출하지 않는 것이 좋습니다. 그렇게 하면 FxCop이 징징거릴 것입니다.여기에는 다음과 같이 List에서 상속하는 것이 포함됩니다.

public MyTypeCollection : List<MyType>

대부분의 경우 공용 API는 적절하게 IList(또는 ICollection 또는 IEnumerable)를 노출합니다.

자신만의 사용자 지정 컬렉션을 원하는 경우 List 대신 Collection에서 상속하여 FxCop을 조용하게 유지할 수 있습니다.

자신만의 컬렉션 클래스를 생성하기로 선택한 경우 다음의 유형을 확인해야 합니다. System.Collections.ObjectModel 네임스페이스.

네임스페이스는 구현자가 사용자 지정 컬렉션을 더 쉽게 만들 수 있도록 기본 클래스를 정의합니다.

실제 목록에 대한 액세스를 보호하려면 내 컬렉션을 사용하는 경향이 있습니다.비즈니스 객체를 작성할 때 객체가 추가/제거되고 있는지 알기 위해 후크가 필요할 가능성이 있습니다. 그런 의미에서 BOCollection이 더 나은 아이디어라고 생각합니다.필요하지 않은 경우 List가 더 가볍습니다.또한 일종의 프록시가 필요한 경우 IList를 사용하여 추가 추상화 인터페이스를 제공하는지 확인할 수도 있습니다(예:가짜 컬렉션은 데이터베이스에서 지연 로드를 유발합니다)

하지만...Castle ActiveRecord나 다른 성숙한 ORM 프레임워크를 고려해 보는 것은 어떨까요?:)

대부분의 경우 나는 단순히 List 방식을 사용합니다. 이는 90%의 시간에 필요한 모든 기능을 제공하고 '추가'가 필요할 때 List 방식을 상속하여 추가 비트를 코딩하는 것입니다. .

나는 이렇게 할 것이다:

using BusinessObjectCollection = List<BusinessObject>;

이는 완전히 새로운 유형이 아닌 별칭을 생성할 뿐입니다.나는 List<BusinessObject>를 직접 사용하는 것보다 나중에 이를 사용하는 코드를 변경하지 않고도 컬렉션의 기본 구조를 자유롭게 변경할 수 있기 때문에 선호합니다(동일한 속성과 메서드를 제공하는 한).

이것을 시도해 보세요:

System.Collections.ObjectModel.Collection<BusinessObject>

CollectionBase와 같은 기본 메소드를 구현할 필요가 없습니다.

이게 방법이다:

배열을 반환하고 수락 IEnumerable<T>

=)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top