2011-11-04 3 views
0

ID가 int 인 여러 객체가 있습니다. 예를 들어 productId가있는 Product 클래스와 customerId가있는 Customer 클래스가 있습니다. 때로는 ID가 섞이기 쉽다고 생각합니다. 예를 들어 하스켈에서와 같이 형식 시스템에서 해당 형식을 구별하도록 솔루션을 생각해 봅니다.C# 사전의 안전성을 향상시킬 수있는 가능한 솔루션

Dictionary<int, Product> products; 
Dictionary<int, Customer> customer; 
Dictionary<int, List<Customer>> customersByProduct; 

customerByProduct[what_id?].Add(new Customer()) 

을 지금 사전으로 사용 뭐죠 혼합이 사전은 가능한 사용하는 코드가있을 때 : 내가 ID로 빠른 액세스를 위해 개체를 저장 여러 사전을 때

이 문제는 가장 명백한입니다 특히 더 복잡한 사전 설정이 있고 개체의 ID가 여러 개인 경우에 유용합니다.

상황을 개선 할 수있는 몇 가지 사고 게임 나 두 가지 해결책, 그리고 기본적으로 그것을 처리하는 다른 좋은 방법이 있다면 나는 무엇을 입력하고, 그 좋은 생각이라면?

지금까지 나는 약간 혼란스러운 느낌이 들었다. 문제의 코드는 현재 작성 중입니다. 따라서 이러한 유형의 버그가 발생하더라도 알지 못하지만, 나중에 다른 개발자가 돌아와서 뭔가를 변경/추가해야 할 때 큰 위험이 있다고 생각합니다.

private struct CustomerId 
{ 
    public CustomerId(int id) 
    {this.id = id;} 
    public override string ToString() 
    {return id.ToString();} 

    public int id; 
} 

private enum ProductId { } 

void Main() 
{ 
    var customers = new Dictionary<CustomerId, string>(); 
    var products = new Dictionary<ProductId, string>(); 

    customers[new CustomerId(1)] = "Customer1"; 
    customers[new CustomerId(2)] = "Customer2"; 
    customers[new CustomerId(3)] = "Customer3"; 

    products[(ProductId)1] = "Product1"; 
    products[(ProductId)2] = "Product2"; 
    products[(ProductId)3] = "Product3"; 

    customers.Dump(); 
    products.Dump(); 

    customers[new CustomerId(2)].Dump(); 
    products[(ProductId)3].Dump(); 

    int cid = customers.Keys.First().id; 
    int pid = (int)products.Keys.First(); 
    cid.Dump(); 
    pid.Dump(); 
} 

+1

id 값을 혼합하는 데 실제로 문제가 있습니까? 그렇지 않다면 결코 발생하지 않을 문제를 해결하는 데 시간을 낭비하게됩니다. –

+0

아니요 :) 컨텍스트는 우리의 핵심 로직의 큰 덩어리가 처음부터 재 작성된다는 것을 의미합니다. 오래된 솔루션은 이러한 구조로 시작하지 않았습니다. 컴파일러가 더 많은 오류를 발견하면 더 많은 오류가 발생한다고 생각할 수 있습니다. 버그가 실제로 나타나기 전에 처음부터 구현하는 것이 가장 좋습니다. 어쨌든, 제가 왜이 질문을 쓴 이유 중 일부는 그 좋은 아이디어가 있는지 아닌지 아는 것이 었습니다. – viblo

+0

가상의 문제를 해결하기 전에 실제 문제를 해결하는 것이 좋습니다. OTOH, 이것이 한 번 문제가된다면 어디서나 문제를 해결하는 것이 좋을 것이라고 말하고 싶습니다. 그러나 문제가 한 번 발생하기 전에. –

답변

3

Dictionary은 뭔가 당신이 명확하게 내부 원시 사전을 개최한다 CustomersRepository 같은 클래스를 만들 수 있습니다로 전진하는 것을 시도하면 매우 낮은 수준의 클래스입니다 (예 linqpad에서 직접 실행할 수 있습니다) GetCustomerById(int id) 또는 int AddCustomer(Customer toAdd)과 같은 더 나은 명명 된 메서드를 노출하여 Dictionary에 액세스 할 수 있습니다.

당신의 예제에서 당신이 섞인 아이디를 시작한 순간과 그들이 자연스럽게 나오는 곳이 불분명합니다.

두 가지 방식 모두 저에게 너무 해킹 된 것처럼 보입니다.

3

이렇게하는 방법 중 하나입니다. 암시 운영자가 쉽게 식별 어디에 사용하실 수 있습니다

struct Identifier<TEntity> 
{ 
    private int _id; 

    public Identifier(int id) 
    { 
     _id = id; 
    } 

    public int Id { get { return _id; } } 

    public static implicit operator int(Identifier<TEntity> identifier) 
    { 
     return identifier.Id; 
    } 

    public static implicit operator Identifier<TEntity>(int id) 
    { 
     return new Identifier<TEntity>(id); 
    } 

    // todo: implement compare logic 
} 

: 당신은 같은 새로운 각 엔티티에 대한 구현 (또는 모델 또는 DTO 또는 당신이 가지고)을 만들 필요에서 당신을 방지하기 위해 식별자가 일반적인 만들 수 있습니다 int 치의 예상과 다른 방법은 주위, 즉됩니다

static void UpdateFoo(int id, Foo foo) 
    { 
     // do something 
    } 

    static void Main() 
    { 
     Identifier<Foo> identifier = 1; 
     UpdateFoo(identifier, new Foo()); 
    } 

지금 당신은 스스로에게 물어 할 수있는 진짜 문제는 당신이 정말로 외부 식별자를할지 여부입니다. 왜 이드를 엔티티 클래스에 넣지 않으시겠습니까?

class EntityBase 
{ 
    public int Id { get; protected set; } 

    // tood: implement compare logic 
} 

class Foo : EntityBase 
{ 
    public string Name { get; set; } 
} 

이제 사전 대신 집합을 사용하여 2 개의 인수를 계속 전달하지 않아도됩니다.

+0

흥미로운 솔루션! 예, 각 클래스에 대해 동일한 것을 만들지 않아도되는 것이 더 편리합니다. HashSet의 문제점은 ID가 모두있는 경우 개체를 일정 시간 내에 다시 얻을 수 없다는 것입니다. – viblo

+0

그래서 우리는 100 개의 테이블이 있다면 int를 표현하는 100 가지 방법을 갖게 될 것입니까? 소리가 나에게 좋지 않습니다. 모든 캐스팅은 단순히 일을하는 것이 아닙니다. 그리고 가장 중요한 것은, 그 신분의 출처는 무엇입니까 ? 일반적으로 RDBMS는 모든 100 개의 테이블이 단일 유형의 키를 공유하므로 모든 접근법이 매우 의심 스럽습니다. –

+0

@viblo - 아이디 만 가지고 돌아 왔습니까? 당신이 무슨 뜻인지 이해가 확실하지 않습니다 ... HashSet에는 O (1) 삽입 시간이 있습니다. 이드 만있을 때 쉽게 제거 할 수 없다는 것을 의미합니까? Dictionary를 hashSet보다 선호하는 것에 대한 좋은 주장이 될 것입니다 ... – Polity

관련 문제