2010-03-24 8 views
4

(일부 네트워크 클래스에서) GUID가 많이 (+2000) 있으며 내 프로그램은 메시지를 받고 관련 작업을 수행 할 때 그 중 하나를 찾아야합니다.
포지티브 포인트는 하드 코드 생성기가 있지만 가장 빠른 방법은 내 목표입니다 (구현 방법을 모르겠습니다).GUID를 찾는 빠른 방법

내 코드는 다음과 같은 것을 수행해야합니다

switch(received guid) 
{ 
case guid1: do job 1; break; 
case guid2: do job 2; break; 
case guid3: do job 3; break; 
case guid4: do job 4; break; 
.... 
} 
+0

"그들 중 하나를 찾아야합니다"는 의미는 무엇입니까? 메시지에서 GUID를 찾는 방법은 무엇입니까? 그것이 당신의 질문의 요점입니까? – Seb

+0

@Seb : 아니, 메시지와 함께 전달 된 GUID가 있지만 내 목록에 동등한 GUID가 있어야합니다 (실제 목록이 없습니다). – Behrooz

+0

현재, 나는 대표자 (세계에서 가장 느린 것) 애호가들로부터 세 가지 대답을 가지고 있습니다. – Behrooz

답변

8

작업을 수행하기위한 인터페이스를 만든 다음 작업을 수행하는 각각의 고유 한 GUID를 알고있는 2000 클래스를 구현합니다. 그런 다음 guid를 키로 사용하여 클래스를 사전에 추가하십시오. 그런 다음 guid를 얻으면 사전에서 객체를 찾아 인터페이스의 메소드를 호출합니다.

+0

좋은 생각, 나는 그것을 구현할 것입니다. (적은 복싱/델리게이트보다 unboxing) – Behrooz

+0

내가 이것에 대해 좋아하는 것은 각 클래스가 책임있는 직업에 대한 코드를 가지고 있기 때문에 당신에게 좋은 관심을 제공한다는 것입니다 에 대한. –

+2

나는 정말로 2000 클래스를 유지하는 것이 문제가되는 유일한 사람입니까? 이 솔루션은 원격으로도 적합한 솔루션입니까? –

15

당신은 키와 값으로 위임 기준으로 GUID로 사전을 만들 수 있습니다. 그러면 빠른 조회가 가능합니다.

+2

어쨌든 커버 아래에 어떤 스위치를 만들지는 사전이 아닙니다. : p – Randolpho

+0

@Randolpho : 그것은 컴파일러에 달려 있습니다. 하지만 문제는 C#에서만 정수 유형과 문자열을 스위치 할 수 있다는 것입니다. –

+1

@Randolpho : 예, 특정 상황에서 C# 컴파일러는 정적 사전을 채우고이를 사용하는 코드를 생성 할 수 있습니다. 다른 시나리오에서는 if else 문의 큰 목록을 생성합니다. 컴파일러가 커버 아래에서 생성하는 것과 상관없이 커다란 유지 보수가 불가능한 스위치를 작성하고 사전을 사용하는 것에서 큰 차이가 있습니다. – Steven

6

Guid를 Dictionary<Guid, Action> 또는 Dictionary<Guid, Task>과 같이 작업을 나타내는 대리자 나 클래스에 매핑하는 해시 테이블을 사용하십시오.

+0

나는 그것이 그가 원하는 것을 확실하게하는 방법이라고 생각한다. – kervin

4

Dictionary<Guid, JobDelegate>은 switch 문보다 빠릅니다.

하지만 프로필을 작성해야합니다.

+0

나는 더 빠르지는 모르지만 2000 + guids를 유지하는 것이 훨씬 더 좋을 것입니다. –

+0

@Matthew : OP에서 코드 생성기에 대해 언급합니다. 세부 사항에 대해서는 잘 모르겠습니다. –

+0

사실, 코드가 생성 되었기 때문에 그것이 유지되지 않는다는 것을 의미하지는 않습니다. –

3

나는 이미 제안 된 사전 접근법의 변형을 보여주고 싶습니다. 이 솔루션을 기반으로 다음을 수행 할 수 있습니다.

1

은 기본 클래스를 정의합니다

public abstract class JobDoer 
{ 
    public abstract void DoJob(); 
} 

2 일 행위자의 장식에 대한 속성을 정의합니다.

public sealed class JobDoerAttribute : Attribute 
{ 
    JobDoerAttribute(string jobDoerId) 
    { 
     this.JobDoerId = new Guid(jobDoerId); 
    } 

    public Guid JobDoerId { get; private set; } 
} 

3 해당 속성으로 장식 된 실제 작업 수행자 클래스를 정의하십시오. 예를 들어 :

[JobDoer("063EE2B2-3759-11DF-B738-49BB56D89593")] 
public sealed class SpecificJobDoer : JobDoer 
{ 
    public override void DoJob() 
    { 
     // Do a specific job 
    } 
} 

(4)이 속성에 정의되어 자신의 ID로 JobDoer 인스턴스를 검색 할 수있는 JobDoerFactory 정의 다음 BuildCache 방법에서

public static class JobDoerFactory 
{ 
    static Dictionary<Guid, JobDoer> cache; 

    static JobDoerFactory() 
    { 
     // Building the cache is slow, but it will only run once 
     // during the lifetime of the AppDomain. 
     cache = BuildCache(); 
    } 

    public static JobDoer GetInstanceById(Guid jobDoerId) 
    { 
     // Retrieving a JobDoer is as fast as using a switch statement. 
     return cache[jobDoerId]; 
    } 

    private static Dictionary<Guid, JobDoer> BuildCache() 
    { 
     // See implementation below. 
    } 
} 

을, 당신은 JobDoer 인스턴스의로드를 할 수있는 반사를 사용하여.

private static Dictionary<Guid, JobDoer> BuildCache() 
{ 
    // This is a bit naive implementation; we miss some error checking, 
    // but you'll get the idea :-) 
    var jobDoers = 
     (from assembly in AppDomain.CurrentDomain.GetAssemblies() 
     from type in assembly.GetTypes() 
     where type.IsSubclassOf(typeof(JobDoer)) 
     let attributes = 
      type.GetCustomAttribute(typeof(JobDoerAttribute), true) 
     where attributes.Length > 0 
     let attribute = attributes[0] as JobDoerAttribute 
     select new { attribute.JobDoerId, type }).ToArray(); 

    var cache = new Dictionary<Guid, JobDoer>(jobDoers.Length); 

    foreach (jobDoer in jobDoers) 
    { 
     // Note that actually a single instance of the job doer is 
     // cached by ID. This means that every Job Doer must be 
     // thread-safe and usable multiple times. If this is not 
     // feasable, you can also create store a set of Func<JobDoer> 
     // objects that enable creating a new instance on each call. 
     cache[jobDoer.JobDoerId] = 
      (JobDoer)Activator.CreateInstance(jobDoer.type); 
    } 
    return cache; 
} 

이 코드를 테스트하지 않았다, 그래서 컴파일 나도 몰라,하지만 난 몇 년 프로젝트에이 메커니즘을 사용했다. 이렇게하면 사전에 연결하지 않고도 새 클래스를 쉽게 정의 할 수 있습니다. 런타임시 자동으로 수행됩니다.

과도한 것처럼 보일 수도 있지만, +2000 JobDoer 클래스를 사용하면 많은 도움이됩니다.

업데이트 : JobDoerAttribute의 아이디어가 마음에 들지 않으면 추상 JobDoer 클래스의 추상 속성으로 구현할 수도 있습니다. 그러나 속성을 사용하면 코드가 매우 명확하고 표현력이 풍부합니다.

+0

좋은 유연한 접근! 리플렉션은 퍼포먼스와 관련하여 가장 좋은 친구는 아니지만 한 번만 수행 된 후 캐시 된 것이므로이 경우 문제가되지 않을 수도 있습니다. –

+0

"단 한 번 수행 된 후 캐시 된 이후"입니다. 정확하게. 이 솔루션의 성능은'switch' 문과 마찬가지로 훌륭합니다. 왜냐하면 C#이 (정적 생성자에서 사전을 작성하여) 커버하고 있기 때문입니다. – Steven

0

Guid 및 동작으로 사전을 만들고 검색하십시오.

관련 문제