2012-08-08 4 views
1

나는 비슷한 문제가 this post에 있습니다.동일한 컬렉션에 다른 유형의 제네릭 클래스 (모두 제네릭 기본 클래스 포함)를 저장하려면 어떻게해야합니까?

나는 또한 수천 개의 게시물을 보면서 특정 기본 클래스를 확장하는 일반 클래스를 기본 클래스 유형의 컬렉션에 넣을 수 있다고 말했다. 나는 이것을 완벽하게 잘 이해한다.

내 문제는 위의 링크 된 게시물과 다른 점이 하나의 기본 방식으로 다릅니다. 내 제네릭 클래스도 제네릭 인 기본 클래스를 가지고 있습니다. 더욱 나쁜 것은 MVVM 애플리케이션 프레임 워크 (사내 구축)의 일부이며 일반 기본 클래스에도 기본 클래스가 있다는 것입니다. 각 기본 클래스는 특정 속성과 기능을 추가하며 다음과 같이 보입니다 :

DataListEntry <T> < - BaseSynchronisableDataType <T> < - BaseAuditDataType < - BaseDataType < - BaseAnimatableDataType

응용 프로그램 컬렉션 클래스가 사용하는 유사한 내가 nheritance :

DataList에 <T> < - BaseSynchronisableCollection <T> < - BaseAnimatableCollection <T> < - BaseCollection <T> < - SortableObservableCollection <T>

더 나쁜 여전히 각 일반 선언에는 제약 조건이 있습니다. 오 즉, 예를 들어, BaseSynchronisableDataType <T>의 정의는 다음과 같습니다

public abstract class BaseSynchronisableDataType<T> : BaseAuditDataType, 
    ISynchronisable<T>, ICloneable<T>, IEquatable<T> where T : class, ICloneable<T>, 
    IEquatable<T>, new() 

그래서 각 제네릭 컬렉션 형식은 일반적인 기본 클래스에 이러한 제약을 통해 연결되어 있습니다. 다행히도 지금까지 내 문제의 규모를 알 수 있습니다.

나는 위에서 언급하지 않은 인터페이스를 사용하여 콜렉션에서 해당 기본 클래스로 링크를 제거하려고 시도했지만 관련 클래스의 일부 일반 제약으로 인해 실패합니다. 예를 들어, 일부 기본 클래스에는 필수적인 '클래스'제약 조건이 필요하기 때문에 인터페이스 형식의 컬렉션을 만들 수 없으므로 컬렉션 유형이 비 추상 형식이어야한다는 오류가 발생합니다. 매개 변수없는 생성자를 일반 유형 또는 메소드에서 매개 변수 'T'로 사용하기 위해.

나는 모두가 DataList에 <T> 기본 클래스를 확장하는 다른 클래스와 컬렉션을 채울 필요가 : 참고로

마지막 점은 내가 할 노력하고 있어요 정확히 설명합니다. 이 클래스는 이름 만 다르며 정확히 동일한 속성을 갖습니다. 그들은 다음과 같이 선언된다 : 당신은 어떤 아이디어가 있다면

public class Writer : DataListEntry<Writer>  
public class Artist : DataListEntry<Artist>etc. 

가, 다음 날 ... 나는 이미이 문제에 2 일 동안 고통을했습니다 알려 주시기 바랍니다 내 상사는 것도 너무 만족입니다! 미리 감사드립니다, Sheridan.

+0

이 솔루션은 실제로 컬렉션의 항목을 사용하여 수행해야하는 작업에 따라 달라집니다. 즉, 일단 컬렉션에 이러한 항목이 모두 있으면 컬렉션을 열거 할 때 각 항목으로 무엇을 할 것입니까? – Jay

+0

이것은 WPF 응용 프로그램입니다. Type 객체를 전달 받고 UI에서 표시 할 컬렉션에서 해당 유형의 각 DataListEntry를 복구해야합니다. 그런 다음이 DataListEntry 유형 중 하나를 표시 할 수있는 컬렉션 객체가 UI에 필요합니다. – Sheridan

+0

"해당 유형의 각 DataListEntry"라고 말하면 해당 유형을 실제로 의미합니까, 아니면 해당 유형이 일반적인 인수인지 의미합니까? 예를 들어'DataListEntry '이 전달 되었습니까, 아니면'MyType'이 전달되고'DataListEntry '을 반환해야합니까? – Jay

답변

0

좋아요 ... 비록 BaseSynchronisableDataType 작성을 목적으로 이길 것 같다, 그래서 문제는 내가 BaseDataListEntry 클래스로 인해의 일반적인 NOT 때 다음

DataList<Artist> artists = new DataList<Artist>(); 

를 선언 할 수 있었다 generic BaseSynchronisableCollection<T> 클래스의 일반 제약은 DataList<T>이 확장됩니다. TBaseDataListEntry 클래스가 확장 할 수없는 유형이 BaseSynchronisableDataType<T>이어야하며 일반 적이기 때문에 확장 할 수 없습니다. 클래스가 일반 적이 지 않으므로 DataList<T>의 모든 다른 컬렉션을 DataList<BaseDataListEntry> 컬렉션에 넣을 수 있습니다 (사용자 선택에 따라 한 번에 하나씩).

해결 방법은 IBaseSynchronisableDataType<T> 인터페이스를 만들고이를 구체 BaseSynchronisableDataType<T> 클래스 대신 제네릭 제약 조건으로 사용하는 것입니다. 그렇다면 BaseDataListEntry 클래스에서 구현 했으므로 이제 모든 제약 조건이 충족됩니다. 왜 내가 이전에 그것을 보지 못했는지 확신 할 수 없다.

시간 내 주셔서 감사합니다.

6

당신이 클래스 Foo<Child>ChildParent의 서브 클래스에도 Foo<Parent>의 서브 클래스가 아닌 것을 understand- 할 필요가 여기 플레이의 핵심 원칙이있다. 즉, List<Foo<Parent>>에는 List<Foo<Child>>의 인스턴스가 Strings 또는 Int32를 포함 할 수있는 것 이상 포함 할 수 없습니다. (위의 문이 사실로해야하는 이유 컴파일 나던하지만, 설명)

이 사건이 왜, 다음 코드를 상상 이해하기 :

var myIntList = new List<Int>(); 
var myObjectList = (List<Object>)myIntList; 

// Uh oh, now I can add a string to a list of integers... 
myObjectList.Add("Foo"); 

curiously recurring template pattern의 사용이 사이의 상속 계층 구조를 제거 모든 수업. 그들은 기본 클래스를 더 이상 공유하지 않기 때문에 더 구체적인 목록에 넣을 수는 없습니다. List<Object>

아마도 가장 좋은 방법은 DataListEntry가 구현하는 비 제너릭 인터페이스를 만드는 것일 수 있습니다. 그 인터페이스. 인터페이스가 해당 유형의 인스턴스에서 필요한 모든 구성원을 제공하면 모두 설정됩니다. 예를 들어

:

다음
public interface IDataListEntry { 
    bool QuacksLikeADuck { get; } 
    bool WalksLikeADuck { get; } 
} 

public abstract class DataListEntry<T> : IDataListEntry where ... { 
    // Implement these in subclasses 
    abstract bool QuacksLikeADuck { get; } 
    abstract bool WalksLikeADuck { get; } 
} 

을 수행 할 수 있습니다

List<IDataListEntry> myDataListEntries = new List<IDataListEntry>(); 
myDataListEntries.Add(new Writer(...)); 
myDataListEntries.Add(new Artist(...)); 
IEnumerable ducks = myDataListEntries.Where(dle => dle.WalksLikeADuck && dle.QuacksLikeADuck); 

또는 (상황에 아마 더 적절한), 당신의 특정 인스턴스에서 T의 유형을 알 필요가 있다면 IDataListEntry :

public interface IDataListEntry { 
    Type TheTypeOfT { get; } 
} 

public class DataListEntry<T> : IDataListEntry where ... { 
    Type TheTypeOfT { get { return typeof(T); } } 
} 

다음 :

List<IDataListEntry> myDataListEntries = new List<IDataListEntry>(); 
myDataListEntries.Add(new Writer(...)); 
myDataListEntries.Add(new Artist(...)); 
IEnumerable artists = myDataListEntries.Where(dle => typeof(Artist).IsAssignableFrom(dle.TheTypeOfT)); 
+0

전체 응답을 보내 주셔서 감사합니다. 기본 클래스는 일반적이며 필요한 기본 클래스 또는 인터페이스의 특정 메서드를 호출하기 때문에 제약이 있으므로 불행히도 이것은 필수적입니다. 내 사용자 정의 DataList 컬렉션 클래스가 필요한 기능을 제공하고 위의 이유로 클래스 제약 조건이 필요하기 때문에'List '에 대한 아이디어를 사용할 수 없습니다. 이것은 정말로 문제입니다. 현재 가능한 한 많은 제약 조건을 없애고 가능한 경우 기본 클래스 대신 인터페이스를 사용하려고 시도하고 있지만 필수 기능을 제공하므로 어렵습니다. 감사. – Sheridan

0

나는 기본으로 돌아가서 몇 가지 간단한 linq를 사용하여 클래스 필터 목록을 얻습니다.

유형 객체 DataList<object> L의 목록을 선언하면 유형을 묻는 메시지가 나타나면 L.OfType<Type>()을 호출하여 목록을 필터링합니다. 객체는 결국 사용할 수있는 가장 일반적인 것입니다. 당신은 모든 타입이 확장 된 기본 타입을 사용할 수 있을지도 모르겠다. 왜냐하면 그 타입에 대한리스트를 선언 할 수 있는지 없는지 나는 알지 못하기 때문이다.

내 자신의 코드로, 나는 유사한 것을 달성하기 위해 일반적인 제약 조건을 사용합니다.

public abstract class BusinessObjectBase : //some interfaces 
{ 
    //class stuff and events 
} 

나는 나의 기본 클래스를 확장 delcared 개체의 무리가 있고, 임 목록에 추가하는 각 클래스는 모든 BusinessObjectBase을 확장하여 만드는 경우 지금은이

Collection<BusinessObjectBase> temp = new Collection<BusinessObjectBase>(); 
temp.Add(new RXEvents()); 
temp.Add(new RXBattery()); 
temp.Add(new RXBHA()); 

을 할 수 있습니다. 매우 비슷한 것을 시도하고 있지만 기본 구현은 다릅니다. 기본 형식 자체를 템플릿으로 선언하면 기본 형식이 손상됩니다. Base는 Base와 같은 노트이며, 두 가지는 객체 이외의 공통된 것을 구현하지 않습니다.

Base<>Base<X> 또는 Base<Y>과 관련이 없습니다.이

public abstract class BaseSynchronisableDataType<T> : BaseAuditDataType, ISynchronisable<T>, ICloneable<T>, IEquatable<T> where T : MyCustomBaseClass, ICloneable<T>, IEquatable<T>, new() 

처럼 delcared 경우 <T>가 나타내는 모든 개체가 그 자녀 보장되기 때문에 이제 그런 다음, 목록 유형으로 MyCustomBaseClass를 사용할 수 있습니다. 이

+0

답장 보내 주셔서 감사합니다. 내 DataList 클래스는 이전에 예제에서 보여준 것처럼 선언해야했습니다. 필요한 기본 클래스 또는 인터페이스의 특정 메서드를 호출해야하기 때문에이를 일반화하고 제약 조건을 변경해야했습니다. 감사. – Sheridan