관련되지 않은 여러 유형을 저장하고 필요에 따라 특정 유형을 제공해야 하는 상황을 어떻게 처리해야 합니까?

StackOverflow https://stackoverflow.com/questions/54219

  •  09-06-2019
  •  | 
  •  

문제

저는 우리가 사용하는 중요한 내부 테스트 도구에서 사용되는 파일 편집기 작업을 하고 있습니다.도구 자체는 크고 복잡하며, 리팩토링이나 재작성에는 우리가 예측 가능한 미래에 전념할 수 있는 것보다 더 많은 리소스가 필요하므로 대규모 수정에 관해서는 손이 묶여 있습니다..NET 언어를 사용해야 합니다.

파일은 도구에서 사용하는 네 가지 클래스(A, B, C, D라고 함)의 XML 직렬화 버전입니다.모든 것이 정상일 때 클래스는 트리 구조를 형성합니다.우리 편집기는 파일 세트를 로드하고, 역직렬화하고, 파일 간의 관계를 파악하고, 발견할 수 있는 잘못된 상태를 추적하는 방식으로 작동합니다.아이디어는 수많은 오류를 발생시키는 이러한 파일을 수동으로 편집하는 일에서 벗어나는 것입니다.

특정 유형의 오류에 대해 문제가 있는 모든 파일의 컬렉션을 유지하고 싶습니다.네 가지 클래스 모두 문제가 있을 수 있으므로 코드 중복을 최대한 줄이고 싶습니다.중요한 요구 사항은 사용자가 항목을 세트로 가져올 수 있어야 한다는 것입니다.예를 들어 오류가 있는 모든 A 객체를 가져와야 하며 전체 컬렉션을 반복하여 원하는 것을 선택하라고 지시하는 것은 a에 비해 허용되지 않습니다. GetAs() 방법.그래서 제가 처음 생각한 것은 오류를 표시하기 위해 역직렬화된 개체와 일부 메타데이터를 관련된 일반 항목을 만드는 것이었습니다.

public class ErrorItem<T>
{
    public T Item { get; set; }
    public Metadata Metadata { get; set; }
}

그런 다음 사용자가 필요할 때 특정 클래스의 항목을 추출하는 도우미 메서드와 함께 모든 오류 항목을 보유할 수 있는 컬렉션 클래스를 갖게 됩니다.여기서 문제가 시작됩니다.

어떤 클래스도 공통 조상으로부터 상속받지 않습니다(다음을 제외함). Object).이것은 아마도 초기 디자인의 실수였을 것입니다. 그러나 며칠 동안 생각해 본 결과 클래스에는 실제로 각 항목을 고유하게 식별하는 GUID 속성 외에는 공통점이 많지 않으므로 원래 디자이너가 왜 그렇게 했는지 알 수 있습니다. 상속을 통해 관련시키지 않았습니다.이는 통합 오류 컬렉션이 다음을 저장해야 함을 의미합니다. ErrorItem<Object> 들어오는 것을 제한하는 기본 클래스나 인터페이스가 없기 때문입니다.그러나 이로 인해 이 통합 컬렉션에 대한 아이디어가 나에게 약간 개략적으로 다가왔습니다.

Public Class ErrorCollection
{
    public ErrorItem<Object> AllItems { get; set; }
}

그러나 이는 공개 인터페이스에 영향을 미칩니다.내가 정말로 원하는 것은 적절한 것을 반환하는 것입니다. ErrorItem 다음과 같은 일반적인 유형:

public ErrorItem<A>[] GetA()

저장만 할 수 있기 때문에 불가능합니다. ErrorItem<Object>!나는 머리 속에서 몇 가지 해결 방법을 검토했습니다.대부분 그들은 새로운 것을 만드는 것을 포함합니다 ErrorItem 즉석에서 적절한 유형을 사용하지만 약간 추악한 느낌이 듭니다.또 다른 생각은 Dictionary 항목을 유형별로 정리하고 싶지만 여전히 옳지 않은 것 같습니다.

여기에 도움이 될 수 있는 어떤 종류의 패턴이 있나요?이 문제를 해결하는 가장 쉬운 방법은 A, B, C 및 D가 파생되는 기본 클래스를 추가하는 것이라는 것을 알고 있지만 원본 도구에 가능한 한 적은 영향을 미치려고 노력하고 있습니다.초기 도구를 변경하기 위해 추진해야 할 만큼 해결 방법의 비용이 너무 큽니까?

도움이 되었습니까?

해결책

A, B, C, D에 공통점이 없다면 기본 클래스를 추가해도 실제로는 아무 것도 얻을 수 없습니다.이는 빈 클래스일 뿐이며 실제로는 객체와 동일합니다.

저는 제네릭 없이 ErrorItem 클래스를 만들고, Item을 객체로 만들고, 참조된 객체를 사용하고 싶을 때 일부 캐스팅을 수행합니다.Guid가 아닌 A, B, C 또는 D 클래스의 속성이나 메서드를 사용하려면 어쨌든 캐스팅해야 했습니다.

다른 팁

이것이 당신이 찾고 있는 것입니까?

private List<ErrorItem<object>> _allObjects = new List<ErrorItem<object>>();

public IEnumerable<ErrorItem<A>> ItemsOfA
{
    get
    {
        foreach (ErrorItem<object> obj in _allObjects)
        {
            if (obj.Item is A)
                yield return new ErrorItem<A>((A)obj.Item, obj.MetaData);
        }
    }
}

캐시하고 싶다면 ItemsOfA 당신은 쉽게 그렇게 할 수 있습니다 :

private List<ErrorItem<A>> _itemsOfA = null;

public IEnumerable<ErrorItem<A>> ItemsOfACached
{
    if (_itemsOfA == null)
        _itemsOfA = new List<ErrorItem<A>>(ItemsOfA);
    return _itemsOfA;
}

지금까지 제가 제시할 답변은 friguybob과 Mendelt Siebenga의 답변을 조합한 것입니다.

Mendelt Siebenga가 지적한 것처럼 기본 클래스를 추가하면 네임스페이스가 오염되고 비슷한 문제가 발생할 뿐입니다.컬렉션에 넣을 수 있는 항목을 더 잘 제어할 수 있지만 여전히 저장해야 합니다. ErrorItem<BaseClass> 여전히 일부 캐스팅을 수행하므로 동일한 근본 원인에 대해 약간 다른 문제가 발생합니다.이것이 내가 게시물을 답변으로 선택한 이유입니다.그것은 무슨 일이 있어도 일부 캐스트를 수행해야 한다는 점을 지적하고 KISS는 추가 기본 클래스와 제네릭이 너무 많다고 지시합니다.

나는 솔루션 자체가 아니라 다음 사항을 상기시켜주는 friguybob의 답변을 좋아합니다. yield return, 캐시되지 않은 버전을 더 쉽게 작성할 수 있습니다(LINQ를 사용하려고 했습니다).캐시된 버전이 조금 더 현명하다고 생각합니다. 하지만 예상되는 성능 매개변수로 인해 캐시되지 않은 버전이 눈에 띄게 느려지지는 않습니다.

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