2015-07-23 6 views
3

Цель:Смешивание ковариационной и контрвариацию

Итерация по следующей коллекции

var collection = new IImportTrigger<EventArgs>[] 
{ 
    new FileSystemImportTrigger() 
    , new TimerImportTrigger() 
}; 

таким образом

foreach (var trigger in collection) 
{ 
    trigger.Import += trigger.OnImport; 
} 

Это то, что я до сих пор

public delegate void ImportTriggerEventHandler<in T>(object sender, T args) where T : EventArgs; 

public interface IImportTrigger<out T> where T : EventArgs 
{ 
    event ImportTriggerEventHandler<T> Import; 
    void OnImport<T1>(object sender, T1 args) where T1 : EventArgs; 
} 

public class FileSystemImportTrigger : IImportTrigger<FileSystemEventArgs> 
{ 
    public event ImportTriggerEventHandler<FileSystemEventArgs> Import; 

    public void OnImport<T>(object sender, T args) where T : EventArgs { } 
} 

public class TimerImportTrigger : IImportTrigger<ElapsedEventArgs> 
{ 
    public event ImportTriggerEventHandler<ElapsedEventArgs> Import; 

    public void OnImport<T>(object sender, T args) where T : EventArgs { } 
} 

Ожидания:

Я хотел бы определить IImportTrigger только один общий параметр.

Проблема:

Если я изменить определение интерфейса к следующему (уведомления общий аргумент T не ковариантны больше).

public interface IImportTrigger<T> where T : EventArgs 
{ 
    event ImportTriggerEventHandler<T> Import; 
    void OnImport(object sender, T args); 
} 

и, следовательно,

public class FileSystemImportTrigger : IImportTrigger<FileSystemEventArgs> 
{ 
    public event ImportTriggerEventHandler<FileSystemEventArgs> Import; 

    public void OnImport(object sender, FileSystemEventArgs args) { } 
} 

public class TimerImportTrigger : IImportTrigger<ElapsedEventArgs> 
{ 

    public event ImportTriggerEventHandler<ElapsedEventArgs> Import; 

    public void OnImport(object sender, ElapsedEventArgs args) { } 
} 

я не буду в состоянии создать общий тип для моей коллекции

var collection = new IImportTrigger<EventArgs>[] 
{ 
    new FileSystemImportTrigger() 
    , new TimerImportTrigger() 
}; 

, поскольку Generic параметр не выводится безопасной больше.

Вопрос:

Есть ли способ, чтобы выполнить свой сценарий?

ответ

2

Переключая OnImport, чтобы быть не общим вообще, используйте явный интерфейс, затем создайте еще один производный интерфейс, который не является ковариантным, который имеет общий verson of Onmport, который вы могли бы отключить.

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var collection = new IImportTriggerBase<EventArgs>[] 
     { 
      new FileSystemImportTrigger() 
      , new TimerImportTrigger() 
     }; 

     foreach (var trigger in collection) 
     { 
      trigger.Import += trigger.OnImport; 
     } 
    } 
} 

public delegate void ImportTriggerEventHandler<in T>(object sender, T args) where T : EventArgs; 

public interface IImportTriggerBase<out T> where T : EventArgs 
{ 
    event ImportTriggerEventHandler<T> Import; 
    void OnImport(object sender, EventArgs args); 
} 

public interface IImportTrigger<T> : IImportTriggerBase<T> where T : EventArgs 
{ 
    void OnImport(object sender, T args); 
} 

public class FileSystemImportTrigger : IImportTrigger<FileSystemEventArgs> 
{ 
    public event ImportTriggerEventHandler<FileSystemEventArgs> Import; 

    public void OnImport(object sender, FileSystemEventArgs args) { } 

    void IImportTriggerBase<FileSystemEventArgs>.OnImport(object sender, EventArgs args) 
    { 
     OnImport(sender, (FileSystemEventArgs)args); 
    } 
} 

public class TimerImportTrigger : IImportTrigger<ElapsedEventArgs> 
{ 
    public event ImportTriggerEventHandler<ElapsedEventArgs> Import; 

    public void OnImport(object sender, ElapsedEventArgs args) { } 

    void IImportTriggerBase<ElapsedEventArgs>.OnImport(object sender, EventArgs args) 
    { 
     OnImport(sender, (ElapsedEventArgs)args); 
    } 
} 

Однако это дает вам дополнительный хлам из OnImport(object sender, EventArgs args) метода, который виден на IImportTrigger<T>.


Это было решить вашу проблему, если я где собирается это сделать, и я предполагаю, что правильно вы просто хотите производные классы, чтобы иметь возможность забрать на тот факт, что Import это увольняют, и вы на самом деле не нужно OnImport воздействию, я бы просто сделать

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var collection = new IImportTrigger<EventArgs>[] 
     { 
      new FileSystemImportTrigger() 
      , new TimerImportTrigger() 
     }; 
    } 
} 

public delegate void ImportTriggerEventHandler<in T>(object sender, T args) where T : EventArgs; 

public interface IImportTrigger<out T> where T : EventArgs 
{ 
    event ImportTriggerEventHandler<T> Import; 
} 

public abstract class OnImportBase<T> : IImportTrigger<T> where T: EventArgs 
{ 

    public event ImportTriggerEventHandler<T> Import; 

    protected virtual void OnImport(object sender, T args) 
    { 
     var tmp = Import; 
     if (tmp != null) 
     { 
      tmp(this, args); 
     } 
    } 
} 

public class FileSystemImportTrigger : OnImportBase<FileSystemEventArgs> 
{ 
    protected override void OnImport(object sender, FileSystemEventArgs args) 
    { 
     DoSomeExtraStuffBeforeImport(); 
     base.OnImport(sender, args); 
    } 

    private void DoSomeExtraStuffBeforeImport() 
    { 
    } 
} 

public class TimerImportTrigger : OnImportBase<ElapsedEventArgs> 
{ 
    protected override void OnImport(object sender, ElapsedEventArgs args) 
    { 
     base.OnImport(sender, args); 
     DoSomeExtraStuffAfterImport(); 
    } 

    private void DoSomeExtraStuffAfterImport() 
    { 
    } 
} 

Это избавляется от подписки на событие, и вместо этого обрабатывает его как переопределение (который является обычной модели в .NET событий).

Смежные вопросы