【问题标题】:Is there a more elegant way to do this in .NET 4.0?在 .NET 4.0 中是否有更优雅的方法来执行此操作?
【发布时间】:2010-11-10 00:20:39
【问题描述】:

C# 4.0 似乎不支持覆盖参数的协方差(使用“in”关键字);是这样吗?

如果是这样,有没有更优雅的方法来做到这一点?

上下文

public interface IBaseEvent { /* ... */ }

public interface IDerivedEvent : IBaseEvent { /* ... */ }

public class MoreDerivedEvent : IDerivedEvent { /* ... */ }

我有一组处理MoreDerivedEvent 的类。由于事件处理代码的限制,我只能为MoreDerivedEvent注册一个事件处理程序,我不知道它会将注册接口作为事件处理(我不相信它会,因为指导是明确使用类)。因此,为了适当地处理事件,我定义了如下处理程序:

public class BaseType
{
    protected virtual void Handle(IBaseEvent @event) { /* Do Base Stuff */ }
}

public class DerivedType
{
    protected virtual void Handle(IDerivedEvent @event)
    {
        /* Do Derived Stuff */
        Handle((IBaseEvent)@event);
    }

    protected override sealed void Handle(IBaseEvent @event)
    {
        base.Handle(@event);
    }
}

这显然不能提供真正的继承,如果我不能解决这个问题,我可能只会扁平化从DerivedTypeBaseType 派生的类型。但我想我会先把它放到 Stack Overflow 社区。​​p>

【问题讨论】:

    标签: c# .net-4.0 overriding contravariance


    【解决方案1】:

    首先,参数类型协方差不是类型安全的。假设我们允许参数类型协方差:

    class B 
    {
        public virtual void Frob(Animal a)
        {
        }
    }
    class D : B
    {
        public override void Frob(Giraffe g)
        {
        }
    }
    ....
    B b = new D();
    b.Frob(new Tiger());  // Calls D.Frob, which takes a giraffe.
    

    不,协方差根本不是你想要的。这是不安全的。您希望返回类型的协方差,而不是参数类型。关于你想要逆变的参数类型:

    class B 
    {
        public virtual void Frob(Giraffe g)
        {
        }
    }
    class D : B
    {
        public override void Frob(Animal a)
        {
        }
    }
    ....
    B b = new D();
    b.Frob(new Giraffe());  // Calls D.Frob, which takes any animal.
    

    那里没问题。

    不幸的是,C# 既不支持返回类型协变也不支持参数类型逆变。对不起!

    【讨论】:

    • 感谢对协方差的更正;我已经更新了问题和标签。
    【解决方案2】:

    首先你需要一个接口来指定逆变器

    public interface IBaseHandler<in T> where T : IBaseEvent
    {
        void Handle(T handle);
    }
    

    然后你可以定义一个基类来做'base stuff'

    public class BaseType<T> : IBaseHandler<T> where T : IBaseEvent
    {
        public virtual void Handle(T handle) { /* do base stuff */} 
    }
    

    这将允许您覆盖 MoreDerivedEvent

    public class MoreDerivedType : BaseType<MoreDerivedEvent>
    {
        public override void Handle(MoreDerivedEvent handle)
        {
            base.Handle(handle);
        }
    }
    

    【讨论】:

    • +1 - 这是一种有趣的方法。在这种情况下,我不喜欢它,因为它引入了一个不会被使用的接口,并且根据定义会导致我的受保护方法变为公共的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多