2009-03-19 2 views
2

유형 안전 일반 가방을 모두 구현해야하는 항목이 있어야합니다.제네릭 인터페이스를 모두 구현하는 유형의 유형 안전 백을 만들려면 어떻게해야합니까?

var stringItem = new IItem<string>(); 
var numberItem = new IItem<int>(); 
var items = new List<IItem<T>>(); //T of course doesn't accomplish what I want 

items.Add(stringItem); 
items.Add(numberItem); 

뭔가 같은 : 다음

interface IItem 
{ 
    object Value { get; set; } 
} 

//Update: 2009-03-19 03:08 PM MST 
//Added the following interface for clarity of my question 

interface IItem<T> : IItem 
{ 
    new T Value { get; set; } 
} 

, 내가 할 수있는 :

var items = new List<IItem>(); 

그러나 나는 내 가방에 형태의 안전성을 잃게

욕망은 그런 짓을하는 것입니다 . 그래서, Dictionary 생각 :

var dict = new Dictionary<Type, List<IItem<T>>>(); //T is wrong again 

dict.Add(typeof(string), new List<IItem<string>>); //that sure looks nice 
+0

나는 더 우아한 해결책이 있다는 것을 알고 있습니다. 결국 제네릭 자체가 .NET에 추가되었습니다. 아마도 C# 4.0의 역학은이 답변에 대한 더 명확한 경로를 제공 할 것입니다. 나는 우리 모두가 현명한 타입 응답을 이해할 정도로 똑똑하지 않다고 가정하고 있습니다. :) –

+0

혼합 가방으로 무엇을 할 계획인지 대략 설명한다면 도움이 될 것입니다. –

+0

불쾌한 object-vs-type-safe-generic 인터페이스 상속과 함께 갈 것입니다. 내 가방의 경우 유형별 항목의 하위 집합을 가져 오는 깔끔한 LINQ 쿼리를 추가했습니다. public IEnumerable > GetItems () {Type t = typeof (T); return (IEnumerable >) Items.Where (i => i.Value.GetType() == t); } –

답변

5

IItem<int>IItem<string>이 다른 사실을 피할 수 있다고 생각하지 않습니다. 일반적인 방법은 기본 인터페이스입니다 :

interface IItem { 
    object Value {get;} 
} 
interface IItem<T> : IItem { 
    new T Value {get;} 
} 

그런 식으로, IItem에 대한 당신의 코드지만, 실제 인스턴스 (즉, 일반적으로 일부 T에 대한 IItem<T>를 구현) stll 내부적으로 강력한 형식있다.

+0

프로토콜 버퍼에서 비슷한 작업을 수행하지만 이름 재사용을 피하십시오. - 약한 타입에는 WeakFoo(), 강한 타입에는 "Foo()"가 있습니다. 이것은 특히 WeakFoo()가 IItem을 반환하고 Foo()가 IItem 을 반환 할 때 도움이됩니다. –

+0

나는 내 질문에 기본 인터페이스를 썼다. :) –

+0

@ iteris - IMO, 중요한 것은 그 사실입니다. : IItem; 당신이 이미 그것을 가지고 있다면, 그렇다면 괜찮습니다 -하지만 진술되지 않았습니다 AFAIK –

1

체크 아웃 PolyDictionary 구현 here합니다.

class Key<T> { public Key() { } } 

class PolyDictionary { 
    private Dictionary<object, object> _table; 

    public PolyDictionary() { 
     _table = new Dictionary<object, object>(); 
    } 

    public void Add<T>(Key<T> key, T value) { 
     _table.Add(key, value); 
    } 

    public bool Contains<T>(Key<T> key) { 
     return _table.ContainsKey(key); 
    } 

    public void Remove<T>(Key<T> key) { 
     _table.Remove(key); 
    } 

    public bool TryGetValue<T>(Key<T> key, out T value) { 
     object objValue; 
     if (_table.TryGetValue(key, out objValue)) { 
      value = (T)objValue; 
      return true; 
     } 
     value = default(T); 
     return false; 
    } 

    public T Get<T>(Key<T> key) { 
     T value; 
     if (!TryGetValue(key, out value)) 
      throw new KeyNotFoundException(); 
     return value; 
    } 

    public void Set<T>(Key<T> key, T value) { 
     _table[key] = value; 
    } 
} 
+0

본질적으로 형식이없는 - 목표가 아닙니다. –

+0

문제에 대한 답변에서 캐스팅을 피할 수는 없습니다. 어딘가에 있어야합니다. 당신은 PolyDictionary 객체 대신에 에 NodeBase를 던지기를 할 수 있습니다.하지만 이것으로 문제가 개선됩니까? –

+0

게다가,이 PolyDictionary *는 * 안전합니다. 내부적으로 데이터를 객체로 저장하므로 무엇을 할 수 있습니까? 궁극적으로, 데이터는 바이트의 덩어리로 타입이 지정되지 않은 메모리 셀에 저장됩니다. –

1

다음과 같은

interface IItem { object Value {get; set;}} 

interface IItem<T> : IItem { T Value {get; set;}} 

var items = new List<IItem>(); 

items.add(new IItem<string>()); 
items.add(new IItem<int>()); 

같은 일을 멀리 얻을 수 있어야하지만 당신은 여전히 ​​당신이 그것을 꺼내 때 약간의 캐스팅을해야 할 것이다.

+0

나는 내 질문에 기본 인터페이스를 썼다. :) 오, 그리고 믿습니다 IItem 은 IItem에서 상속하고 값을 무시해야합니다 ... –

+0

코드 예제를 수정했습니다. IItem 은 IItem에서 상속받은 것으로 간주되었습니다. – Gregg

0

관심있는 값을 복싱하는 유일한 목적의 새 클래스를 만듭니다. -이 클래스는 StringItem 또는 NumberItem 중 하나를 받아 들여야합니다. - 클래스에서 문자열 또는 숫자 항목 멤버에 대한 액세스를 허용해야합니다.

개체를 목록에 넣었 으면 개체를 상자에 넣은 다음 다시 꺼내야합니다.

이것이 C++ 인 경우이 디자인의 오버 헤드는 구현 방법에 따라 추가 포인터 역 참조 이상이어서는 안되지만 핵심 구절은 "boxing"및 "unboxing"입니다.

0
public class GrabBag<T> 
{ 
    private ArrayList inner = new ArrayList(); 

    public void Add(T item) 
    { 
     inner.Add(item); 
    } 

    public IEnumerable<U> Get<U>() where U : T 
    { 
     return inner.OfType<U>(); 
    } 
} 

또는 일반 목록을 사용하고 OfType을 호출 할 수 있습니다. 그것은 더 의미가 있습니다.

관련 문제