2012-05-16 3 views
5

나는 (내가 작업하고있는 게임에서 엔티티를 저장하기 위해) 3 개의 다른 연결된 목록의 클래스가 있습니다. 목록은 모두 동일한 기본 유형을 가진 객체이지만 처리상의 이유로 별도로 유지합니다. IEntity, IObject 및 IUndead는 모두 IEntity에서 상속받습니다.C#, 클래스 내의 다른 목록에 액세스하는 일반적인 방법

public class EntityBucket 
{ 
    public LinkedList<IEntity> undeadEntities; 
    public LinkedList<IEntity> objects; 
    public LinkedList<IEntity> livingEntities; 

    public EntityBucket() 
    { 
     undeadEntities = new LinkedList<IEntity>(); 
     objects = new LinkedList<IEntity>(); 
     livingEntities = new LinkedList<IEntity>(); 
    } 

    public LinkedList<IEntity> GetList(IObject e) 
    { 
     return objects; 
    } 

    public LinkedList<IEntity> GetList(IUndead e) 
    { 
     return undeadEntities; 
    } 

    public LinkedList<IEntity> GetList(ILiving e) 
    { 
     return livingEntities; 
    } 

} 

현재 각 매개 변수를 기반으로 각 목록을 검색하는 3 가지 방법이 있습니다. 각 목록이 어떤면에서 또는 다른 방식으로 자체 접근자를 요구한다는 것을 알고 있기 때문에 3이 있다는 사실은 좋습니다. 인스턴스화 된 객체를 전달하는 것은 이상적이지 않습니다. 유사한 유형의 객체를 사용하지 않고 어딘가에서 목록을 검색하려고 할 수 있습니다. 여기에있는 객체는 GetList 메소드에서도 사용되지 않으며, 사용할 버전을 결정하기위한 용도로만 사용됩니다.

public void Delete(IUndead e, World world) 
{ 

    ..... 
    LinkedList<IEntity> list = buckets[k].GetList(e); 
    ..... 
} 

난 항상 손에서 인스턴스화 된 객체가 없을 수로 (예를 들어, 개체를 렌더링 할 때) 나는이 현재 구현을 좋아하지 않는다 : 여기에 내가 손에 인스턴스화 된 객체가 예입니다. 나는 일반적으로 그렇게하려고 생각하고 있었지만 이것이 내가 원하는 것과 가능한지 확실하지 않다. 이걸로 나는 또한 3 가지 삭제 메소드 (그리고 추가와 같은 다른 것 중 3 개) - 각 타입, IUndead, IObject 및 ILiving에 하나 -이 필요합니다. 나는 이것이 그 일을하는 올바른 방법이 아니라고 생각합니다.

나는 요청에 따라 지금까지 시도한 것을 게시 하겠지만, 제네릭은 오히려 나쁘다. 나는 이것을 읽는 것이 낭비라고 느낀다.

마지막으로 성능이 매우 중요합니다. 내가 조기에 최적화하지는 않아, 이미 코드 작업을하고 있기 때문에 포스트 최적화를하고 있지만 더 빨리 진행할 필요가 있습니다. getlist 메소드는 매우 자주 호출 될 것이고 나는 명시적인 타입 검사를 피하고자한다.

+0

실제로 사용되지 않는다면'GetList' 메소드의 매개 변수는 무엇입니까? 메서드가 아니라 속성으로 목록을 노출 할 수있는 것 같습니다. – Lee

+0

그런데 어떻게했는지는 알지만,이 목록에 액세스하는 각 메소드의 3 가지 버전이 있어야합니다. 나는 3을 원하지 않으며, 나는 하나의 일반적인 버전을 원한다. 명시 적으로 목록을 속성으로 호출하여이 작업을 수행 할 수는 없습니다. 목록 자체는 일반적인 방법으로 검색해야합니다. 선택할 올바른 목록은 일부 유형 또는 다른 유형을 사용하여 결정해야합니다. – Denzil

답변

1

더 나은 인터페이스로 나아 가기위한 더 나은 구현은 어떻습니까? 이 구현으로


public class EntityBucket 
{ 
    public LinkedList<IEntity> Entities; 

    public IEnumerable<T> GetEntities<T>() where T : IEntity 
    { 
    return Entities.OfType<T>(); 
    } 

} 


List<IUndead> myBrainFinders = bucket.GetEntities<IUndead>().ToList(); 

, 더 나은 호출자는 오른쪽 목록 (들)에 각 항목을 추가 할 수 있습니다. 그것은 원래 구현에 대한 요구 사항 이었으므로 아무 문제가없는 것으로 판단됩니다.

public class EntityBucket 
{ 
    Dictionary<Type, List<IEntity>> entities = new Dictionary<Type, List<IEntity>>(); 

    public void Add<T>(T item) where T : IEntity 
    { 
    Type tType = typeof(T); 
    if (!entities.ContainsKey(tType)) 
    { 
     entities.Add(tType, new List<IEntity>()); 
    } 
    entities[tType].Add(item); 
    } 

    public List<T> GetList<T>() where T : IEntity 
    { 
    Type tType = typeof(T); 
    if (!entities.ContainsKey(tType)) 
    { 
     return new List<T>(); 
    } 
    return entities[tType].Cast<T>().ToList(); 
    } 

    public List<IEntity> GetAll() 
    { 
    return entities.SelectMany(kvp => kvp.Value) 
     .Distinct() //to remove items added multiple times, or to multiple lists 
     .ToList(); 
    } 

} 
+0

감사합니다. 시간이 되 자마자이를 구현할 것입니다. 그것이 충분히 빠르면 나는 여기에 돌아올 것이다 – Denzil

+0

그러나 이것을 보았을 때 나는 마음 속에 가지고있는 것과 다소 비슷하게 보였다. – Denzil

3

여러분이 말했듯이 불필요한 객체를 GetList으로 전달하면 형식이 정확하지 않기 때문에 더 나은 인터페이스가 필요합니다.

당신은 같은 것을 할 수있는 :

public List<IEntity> GetList<T>() : where T:IEntity 
{ 
    if(typeof(T)==typeof(IUndead)) return undedEntities; 
    // and so on 
} 

을 그리고 당신은 다음과 같이 호출해야합니다 :

enum EntityTypes { Undead, Alive, Object }; 
public List<IEntity> GetList(EntityTypes entityType) { ... } 

: GetList<IUndead>();

나는 열거 여기에 더 좋은 아이디어라고 생각 그것은 더 깨끗하고 내게 더 이해가됩니다.

편집 : 제네릭 사용은 실제로 그렇게 간단하지 않습니다. 누군가 GetList에 Zombie 유형을 호출 할 수 있습니다.이 유형은 IUndead를 구현하며 인터페이스 구현을 확인해야합니다. 누군가는 IUndead와 IAlive를 구현하는 LiveZombie을 전달할 수도 있습니다. 확실히 enum과 함께 가라.

+1

이 상황에 대한 enum을 만드는 것에 동의합니다. – Tejs

+0

나는 당신의 대답을 좋아합니다. 나는 그것을 받아들이 기 전에 그것을 구현할 것이다. 내 게시물에서 언급하지 않은 것 같지만 실적은 실제로 여기에서 문제입니다. 이 GetList 함수는 초당 수천 번 호출되므로 typeof를 수행하는 것이 약간 두려워요. http://msdn.microsoft.com/en-us/library/ms973858.aspx에 따르면 "유형 비교 연산 - 이 경우 C#, GetType, isInstanceOfType 등의 typeof는 리플렉션 API 중 가장 저렴한 것이지만 저렴한 것은 아닙니다. " "절대로 싼 것이 아닙니다"라는 것에주의하십시오. – Denzil

+0

저는 여러분이 그것을 언급 했으므로 지금 열거 형을 살펴 보겠습니다. 나는 그것에 대해 배웠지 만 어디에서도 실제로 사용하지 못했습니다. – Denzil

1

어때 다음과 같은 걸까요?

public LinkedList<IEntity> GetList(Type type) { 
    if (typeof(IUndead).IsAssignableFrom(type)) return undeadEntities; 
    if (typeof(ILiving).IsAssignableFrom(type)) return livingEntities; 
    if (typeof(IObject).IsAssignableFrom(type)) return objects; 
} 

그럼 당신은 이런 식으로 부를 것이다 :

var myUndeads = GetList(typeof(IUndead)); 
var myLivings = GetList(typeof(ILiving)); 
// etc 

로직의 동일한 유형을 추가하여 삭제에 구현하고, 다른 방법, 당신은 객체의 구체적인 인스턴스를 필요가 없습니다 수 있습니다 그들을 액세스 할 수 있습니다.

IsAssignableFrom 로직은 서브 클래 싱을 잘 처리한다.CatZombie을 가질 수 있습니다. 이는 Zombie에서 파생되며 IUndead을 구현하며 여전히 작동합니다. 이것은 당신은 여전히 ​​하나의 삭제 방법은 다음과 같은 것을 만들 필요가 의미

public void Delete(IEntity e, World world) { 
    if (typeof(IUndead).IsAssignableFrom(type)) undeadEntities.Remove(e); 
    if (typeof(ILiving).IsAssignableFrom(type)) livingEntities.Remove(e); 
    if (typeof(IObject).IsAssignableFrom(type)) objects.Remove(e); 
} 

편집 : 성능에 관한 zmbq의 대답에 귀하의 코멘트를 발견; 이것은 확실히 빠르지 않다. 고성능이 필요한 경우 열거 형 방식을 사용하십시오. 코드가보다 상세 해지고 유지 관리가 더 많이 필요하지만 더 나은 성능을 얻을 수 있습니다.

+0

네, 죄송합니다. 나는 생각을 위해 당신에게 1을 줄 것이다. 이것을 반영하기 위해 내 게시물을 업데이트하는 것이 좋습니다! 죄송합니다 다시 한번 – Denzil

+0

이것은 제네릭을 사용하는 것보다 실제로 더 나쁩니다. generics를 사용하면 String이나 DataSet을 전달하면 컴파일러에서 catch합니다. 그리고 당신은 여전히 ​​IAlive와 IUndead를 구현하는 객체를 얻는 데 어려움을 겪고 있습니다. – zmbq

+1

@zmbq "그리고 당신은 여전히 ​​IAlive와 IUndead를 구현하는 객체를 얻는 데 어려움을 겪고 있습니다." 나는 네가 무슨 뜻인지 모르겠다. 'Delete'는 다중 인터페이스를 잘 처리 할 것입니다. GetList가 다중 인터페이스를 다루지 않는다고 말하는 겁니까? 이 경우 솔루션은 문제를 해결하지 못합니다.그에 대한 수정은 그냥 IAlive과 IUndead 모두를 구현하는 객체를 전달 대해서 이야기하고 – ean5533

0

이름이 LinkedList 인 사전을 구현하고 이름이나 열거 형으로 을 참조 할 수 있습니다.

그런 식으로 목록을 추가하거나 제거하면 구현 문제이며 별도의 클래스는 다루지 않습니다.

+0

처음에는 그렇게 했었지만 코드는 3 가지 유형으로 확장되어 별도로 처리 할 수 ​​있어야했습니다. 그래서 3 개의 연결된 목록이있는 버킷을 추가했습니다. 또한 3 개의 사전을 만들려고 시도했지만 사전 액세스가 상대적으로 느리기 때문에 가장 느린 구현입니다. – Denzil

관련 문제