混合协方差和反方差
本文关键字:方差 混合 | 更新日期: 2023-09-27 18:04:34
目标:
在以下集合上迭代
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参数不再是输出安全的。
问题:
有什么方法可以完成我的场景吗?
通过将OnImport切换为完全非泛型,然后使用显式接口,然后制作另一个非协变的派生接口,该接口具有OnImport的泛型版本,您可以实现它。
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)
方法的额外cruft,该方法在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事件中的正常模式(。