首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >混合协方差与反方差

混合协方差与反方差
EN

Stack Overflow用户
提问于 2015-07-23 21:12:59
回答 1查看 119关注 0票数 3

目标:

迭代以下集合

代码语言:javascript
复制
var collection = new IImportTrigger<EventArgs>[]
{
    new FileSystemImportTrigger()
    , new TimerImportTrigger()
};

以这种方式

代码语言:javascript
复制
foreach (var trigger in collection)
{
    trigger.Import += trigger.OnImport;
}

,这就是我到目前为止所拥有的

代码语言:javascript
复制
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不再是协变的)。

代码语言:javascript
复制
public interface IImportTrigger<T> where T : EventArgs
{
    event ImportTriggerEventHandler<T> Import;
    void OnImport(object sender, T args);
}

因此

代码语言:javascript
复制
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) { }
}

我将无法为我的集合创建一个公共类型

代码语言:javascript
复制
var collection = new IImportTrigger<EventArgs>[]
{
    new FileSystemImportTrigger()
    , new TimerImportTrigger()
};

因为泛型参数不再是输出安全的。

问题:

有什么办法可以完成我的方案吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-07-23 21:53:26

通过将OnImport切换为非泛型,然后使用显式接口,然后再创建另一个不具有OnImport泛型子的非协变的派生接口,您可以实现它。

代码语言:javascript
复制
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,我只想这样做。

代码语言:javascript
复制
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事件中的正常模式)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31598127

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档