2014-02-14 3 views
7

정적 이벤트가 상당히 좋아 보이는 상황이 있지만 다른 사람들의 코드에서 볼 수없는 경우가있어서 중요한 것을 놓치고 있는지 궁금합니다. 이 사이트의 정적 이벤트에 대한 많은 토론을 발견했지만, 대부분 정적 클래스와 같이 관심이없는 상황이나 처음부터 사용하지 않을 상황을 처리합니다.비 정적 클래스의 정적 이벤트

내가 관심있는 내용은 내가 무언가의 많은 인스턴스와 그 인스턴스의 무언가에 반응하는 긴 "매니저"객체의 단일 인스턴스를 가질 수있는 상황입니다. 나에게

public class God { 

    //the list of followers is really big and changes all the time, 
    //it seems like a waste of time to 
    //register/unregister events for each and every one... 
    readonly List<Believer> Believers = new List<Believer>(); 

    God() { 
     //...so instead let's have a static event and listen to that 
     Believer.Prayed += this.Believer_Prayed; 
    } 

    void Believer_Prayed(Believer believer, string prayer) { 
     //whatever 
    } 
} 

public class Believer { 

    public static event Action<Believer, string> Prayed; 

    void Pray() { 
     if (Prayed != null) { 
      Prayed(this, "can i have stuff, please"); 
     } 
    } 
} 

, 이것은 인스턴스 이벤트를하는 것보다 훨씬 깨끗하고 간단한 해결책처럼 보이는 나도 신자 컬렉션에서 변경 사항을 모니터링 할 필요가 없습니다 : 아주 간단한 예를 들어 무슨 뜻인지 설명하기 위해. Believer 클래스가 God 타입 클래스를 "볼"수있는 경우, 때때로 NotifyGodOfPrayer() - 메서드를 대신 사용할 수 있습니다 (몇 가지 비슷한 질문에서 선호되는 대답 임). 그러나 Believer 타입 클래스는 "모델들"- 나는 하나님 클래스에 직접 접근하고 싶지 않거나 직접 접근하고 싶지 않다.

이 접근법에 실제 단점이 있습니까?

편집 : 이미 시간을내어 답변 해 주신 모든 분들께 감사드립니다. 내 예 나쁜 될 수있다, 그래서 나는 내 질문에 명확히하고자 : 나는

  • 확실 해요 오직의 하나 개의 인스턴스가있을 것입니다 상황에서 정적 이벤트의 종류를 사용하는 경우

    을 응용 프로그램만큼 존재 보장 가입자 객체

  • 내가보고 있어요 인스턴스의 수를 실행하는

다음 일이다 거대하다 내가 알지 못하는이 접근법에 잠재적 인 문제점이 있습니까?

해당 질문에 대한 대답이 "예"가 아니라면 대체로 구현을 찾지 않고 있지만 모두 도움을 주셔서 감사합니다. 나는 가장 예쁜 해결책을 찾고 있지 않다. (간단하고 읽기 쉽고 유지하기 쉽도록 내 상을 주어야한다. :)

+0

가능한 복제본 [정적 이벤트는 C#의 비 정적 이벤트와 어떻게 비교합니까?] (http://stackoverflow.com/questions/7045595/how-do-static-events-compare-to-non-static- events-in-c) –

+1

아마도 그 중 하나의 대답은 본 시나리오에서 유용하지 않습니다. 답변 1 (수락 됨) : "정적 이벤트에 대한 인스턴스를 보내지 않음"- 여기에 해당하지 않습니다. 답변 2 : 구독 취소 문제 - 여기에 해당하지 않습니다. 답변 3 : 정적 방법/클래스 - 관심 없음 답변 4 : 3 사용 정적 이벤트에 대한 사례 - 그 중 아무 것도 내 유스 케이스가 아닙니다. 답변 5 : "정적 이벤트는 완전히 끔찍한 것"입니다. – wilford

답변

12

하나 중요한 것은 그들이 이벤트 소유자까지 수집 된 쓰레기 수없는 이벤트에 중독 된 개체 쓰레기 수집 또는 이벤트 핸들러가 벗겨 때까지있다가 발생할 것입니다.당신은 당신이 승진 그들이 Believer.Prayed에 연결되어있는 동안 당신의 RAM에 남아있을 것 같은

new God("Svarog"); 
new God("Svantevit"); 
new God("Perun"); 

신으로 신들을 강등 많은 신들과 다신교 판테온,이 있다면

, 당신의 예에 넣어합니다. 그러면 응용 프로그램에서 신을 누설하게됩니다.


내가 디자인 결정에 대해서도 의견을 말 하겠지만, 당신이 만든 예가 실제 시나리오의 최상의 복사본이 아닐 수 있습니다.

God에서 Believer으로 종속성을 생성하거나 이벤트를 사용하지 않는 것이 더 합리적인 것처럼 보입니다. 좋은 접근법은 신자와 신들 사이에 서있는 이벤트 수집기를 만드는 것입니다. 예를 들어 :

public interface IPrayerAggregator 
{ 
    void Pray(Believer believer, string prayer); 
    void RegisterGod(God god); 
} 

// god does 
prayerAggregator.RegisterGod(this); 
// believer does 
prayerAggregator.Pray(this, "For the victory!"); 

Pray시 메소드가 호출되고, 이벤트 애그리 게이터 (aggregator)가 차례로 God 클래스의 적절한 메소드를 호출합니다. 참조를 관리하고 메모리 누수를 방지하려면 weak references 같은

public class Priest : IPrayerAggregator 
{ 
    private List<WeakReference> _gods; 

    public void Pray(Believer believer, string prayer) 
    { 
     foreach (WeakReference godRef in _gods) { 
      God god = godRef.Target as God; 
      if (god != null) 
       god.SomeonePrayed(believer, prayer); 
      else 
       _gods.Remove(godRef); 
     } 
    } 

    public void RegisterGod(God god) 
    { 
     _gods.Add(new WeakReference(god, false)); 
    } 
} 

로 빠른 팁의 컬렉션 UnregisterGod 방법 또는 보류 신들을 만들 수 있습니다 청취자가 자신의 이벤트 핸들러를 풉니 다 하듯이 일시적 이벤트 대리자를 저장

void Pray() { 
    var handler = Prayed; 
    if (handler != null) { 
     handler(this, "can i have stuff, please"); 
    } 
} 

편집

시나리오 (이벤트 인보 커, 상수 및 단일 이벤트 감시자의 엄청난 숫자)에 대해 추가 한 세부 정보를 염두에두면 효율성면에서 순전히 올바른 시나리오를 선택했다고 생각합니다. 메모리 및 CPU 오버 헤드를 최소화합니다. 나는이 접근법을 일반적으로 취하지 않겠지 만 시나리오에 대해 정적 이벤트는 내가 취할 수있는 매우 실용적인 해결책이라고 설명했습니다.

내가보기에 하나의 단점은 제어의 흐름입니다. 만약 당신이 말한대로 이벤트 리스너가 단일 인스턴스로 생성된다면, 나는 싱글 톤 (anti) 패턴을 사용하고 GodBeliever의 메소드를 직접 호출 할 것입니다.

God.Instance.Pray(this, "For the victory!"); 
//or 
godInstance.Pray(this, "For the victory!"); 

왜? 왜냐하면기도의 수행에 대해보다 세분화 된 통제를하기 때문입니다. Believer의 서브 클래스를 지정해야하는 라인을 특정 일에기도하지 않는 특별한 종류로 결정하면, 이것을 제어 할 수 있습니다.

+0

약한 참조에 대한 +1 – Tseng

+0

나는 당신의 신을 좋아합니다 :) 내 실제 응용 프로그램에서 "God"은 "AutoSaveService"와 같을 것입니다. 응용 프로그램 수명 동안 정확하게 하나의 인스턴스 만 있으므로 여러 인스턴스가 있거나 등록이 취소되었습니다. 정적 이벤트는 중요하지 않습니다. 저는 aggregator-example을 좋아합니다. 실제로는 이런 종류의 접근법을 충분히 자주 사용하지 않을 수도 있습니다. 보통 나는 핸들러를 저장하고 전용 "OnPrayed"메소드를 가지고 있습니다. 예제를 더 짧게 만들기 위해 편집했습니다. – wilford

+0

고마워 :) 어쨌든, 어 그리 게이터 예제는 아마도 너무 장황하다. 제네릭 어 그리 게이터가 유용 할 수 있습니다. 다른 이벤트에 대한 알림을 받고 다른 청취자에게 알릴 수있는 사람. [나는 Caliburn.Micro가 이것을 어떻게 다루는가를 좋아한다.] (http://caliburnmicro.codeplex.com/wikipage?title=The%20Event%20Aggregator). 제대로 사용하지 않으면 가능한 메모리 누수 이외에, 나는 당신의 접근 방식에 문제가 보이지 않는다. –

0

사실 나는 having an instance even이 더 깨끗하고 도전적 일 것이라고 생각한다. 더 읽기 쉽습니다.
인스턴스를 먹이로 보는 것이 훨씬 더 간단하므로 그의기도 이벤트가 발생합니다. 그리고 나는 그것에 대한 개미 단점을 보지 못합니다. 나는 monitor changes이 정적 이벤트를 모니터링하는 것보다 더 많은 허슬이 아니라고 생각합니다. 그러나 목록을 모니터링

... 갈 수있는 올바른 방법입니다 :
변경 목록이 ObservableCollection 수 (및 NotifyCollectionChangedEventArgs에서 살펴) 할 수 있습니다.
에 의해 그것을 모니터 : 이벤트에 대해 알고

public class God { 

    readonly ObservableCollection<Believer> Believers = new ObservableCollection<Believer>(); 

    public God() { 
     Believers = new ObservableCollection<T>(); 
     Believers.CollectionChanged += BelieversListChanged; 
    } 

    private void BelieversListChanged(object sender, NotifyCollectionChangedEventArgs args) { 

     if ((e.Action == NotifyCollectionChangedAction.Remove || e.Action ==  NotifyCollectionChangedAction.Replace) && e.OldItems != null) 
     { 
      foreach (var oldItem in e.OldItems) 
      { 
       var bel= (Believer)e.oldItem;    
       bel.Prayed -= Believer_Prayed; 
      } 
     } 

     if((e.Action==NotifyCollectionChangedAction.Add ||    e.Action==NotifyCollectionChangedAction.Replace) && e.NewItems!=null) 
      { 
       foreach(var newItem in e.NewItems) 
       { 
        foreach (var oldItem in e.OldItems) 
       { 
        var bel= (Believer)e.newItem;    
        bel.Prayed += Believer_Prayed; 
       } 
      } 
     } 
    } 

    void Believer_Prayed(Believer believer, string prayer) { 
     //whatever 
    } 
} 
+0

ObservableCollection은 내가 자주 이것을 수행하는 방법입니다 (btw는 Reset-Action도 처리하는 것을 잊지 마십시오). 그러나 얼마나 많은 코드인지를 유의하십시오. 그리고 100이되면.000 추종자, 그것은 날 때마다 루프를 시작하고 인스턴스 이벤트를 등록하는 바보 같은 느낌. 바인딩을 위해 Believers 컬렉션을 사용하고 싶다면 ObservableCollection을 사용해야합니다.하지만 이벤트를 등록 할 수 있도록 낭비하는 것 같습니다. – wilford

관련 문제