【问题标题】:C# 5.0 Generics: param type inferenceC# 5.0 泛型:参数类型推断
【发布时间】:2013-11-10 18:11:05
【问题描述】:

我一直认为 C# 编译器能够在以下情况下推断类型参数:

class Program
{
    static void Main(string[] args)
    {
        IMessageBus messageBus = null;

       //Here the compiler nags "type params for Publish cannot be inferred from the usage.. .."
        messageBus.Publish(new CorrectorAdded(10));
    }
}

public interface IEvent<out TPayload>
{
    TPayload Payload { get; }
}

public abstract class EventBase<TPayload> : IEvent<TPayload>
{
    public TPayload Payload { get; private set; }

    protected EventBase(TPayload payload)
    {
        Payload = payload;
    }
}

public interface IMessageBus
{
    void Publish<TEvent, TPayload>(TEvent @event) where TEvent : IEvent<TPayload>;

    IDisposable Subscribe<TEvent, TPayload>(Action<TPayload> listener) where TEvent : IEvent<TPayload>;
}

public class CorrectorAdded : EventBase<CorrectorAddedArgs>
{
    public CorrectorAdded(CorrectorAddedArgs payload) : base(payload)
    {
    }

    public CorrectorAdded(int correctorId) : this(new CorrectorAddedArgs(correctorId))
    {
    }
}

public class CorrectorAddedArgs
{
    public int CorrectorId { get; private set; }

    public CorrectorAddedArgs(int correctorId)
    {
        CorrectorId = correctorId;
    }
}

关于为什么会发生这种情况以及如何让类型推断在这种情况下起作用的任何想法?

谢谢。

【问题讨论】:

标签: c# generics type-inference


【解决方案1】:

publish 的接口签名定义了 2 个约束:

void Publish<TEvent, TPayload>(TEvent @event) where TEvent : IEvent<TPayload>;
  1. TEvent 这将是方法参数的签名
  2. TPayload 其中声明 TEvent 必须实现接口 IEvent&lt;TPayload&gt;

如果 Publish 方法只有 TEvent 的约束,那么编译器可以推断用法,因为方法的签名已经定义了类型约束,即,

void Publish<TEvent>(TEvent @event);

上面将允许在没有类型约束的情况下使用方法调用,即,

messageBus.Publish( new CorrectorAdded( 10 ) );
// would be the same as
messageBus.Publish<CorrectorAdded>( new CorrectorAdded( 10 ) );

但是,由于接口定义了第二个约束,编译器不知道TPayload 的意图是什么,因为事件可以实现任意数量的IEvent&lt;TPayload&gt;。但是,如果方法签名确实包含 TPayload 的类型,那么编译器可以实际推断出约束,即

void Publish<TEvent, TPayload>(TEvent @event, TPayload payload) where TEvent : IEvent<TPayload>;

可以在没有类型约束的情况下调用 then 方法:

messageBus.Publish( new CorrectorAdded( 10 ), new FooThatImplementsTPayload() );

【讨论】:

  • 谢谢!这一切都清楚了。并没有让我的生活更轻松,尽管这样 API 看起来确实模棱两可 =)。也许需要扭转局面..
【解决方案2】:

对于那些仍然对替代 API 的外观感到好奇的人,这是我想出的:

class Program
{
    static void Main(string[] args)
    {
        IMessageBus messageBus = null;

        messageBus
            .Event<CorrectorAdded>()
            .Subscribe(eventArgs => { /*skipped*/ });

        //skipped

        messageBus
            .Event<CorrectorAdded>()
            .Publish(new CorrectorAddedArgs(1));
    }
}

public abstract class EventBase
{
    //skipped
}

public abstract class EventBase<TPayload> : EventBase
{
    public IDisposable Subscribe(Action<TPayload> listener)
    {
        //skipped
    }

    public void Publish(TPayload payload)
    {
        //skipped
    }
}

public class CorrectorAdded : EventBase<CorrectorAddedArgs>
{
}

public class CorrectorAddedArgs
{
    public int CorrectorId { get; private set; }

    public CorrectorAddedArgs(int correctorId)
    {
        CorrectorId = correctorId;
    }
}

public interface IMessageBus
{
    TEvent Event<TEvent>() where TEvent : EventBase, new();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多