简体   繁体   English

C#5.0泛型:param类型推断

[英]C# 5.0 Generics: param type inference

I've always been under impression that the C# compiler is able to infer type params in cases like the following: 我一直认为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;
    }
}

Any ideas on why this is happening and how to get the type inference to work in that case? 关于为什么会发生这种情况以及如何在这种情况下使类型推断工作的任何想法?

Thanks. 谢谢。

The interface signature for publish defines 2 constraints: publish的接口签名定义了2个约束:

void Publish<TEvent, TPayload>(TEvent @event) where TEvent : IEvent<TPayload>;
  1. TEvent which will be the signature for the method parameter TEvent ,它将是方法参数的签名
  2. TPayload which states TEvent must implement the interface IEvent<TPayload> TPayload表明TEvent必须实现接口IEvent<TPayload>

If the Publish method only had the constraint of TEvent , then the compiler could infer the usage since the signature of the method already has the type constraint defined, ie, 如果Publish方法只有TEvent的约束,那么编译器可以推断使用,因为方法的签名已经定义了类型约束,即,

void Publish<TEvent>(TEvent @event);

The above would then allow for the method invocation to be used without the type constraint, ie, 以上将允许在没有类型约束的情况下使用方法调用,即,

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

However, since the interface defines the 2nd constraint, the compiler has no idea what the intent is for TPayload since the event can implement any number of IEvent<TPayload> 's. 但是,由于接口定义了第二个约束,因此编译器不知道TPayload的意图是什么,因为事件可以实现任意数量的IEvent<TPayload> However, if the method signature did include the type of TPayload then the complier could actual infer the constraint, ie, 但是,如果方法签名确实包含TPayload的类型,则编译器可以实际推断出约束,即,

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

And then then method could be invoked without the type constraints: 然后可以在没有类型约束的情况下调用方法:

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

To those who are still curious about how an alternative API might look like, here is what I came up with: 对于那些仍然对替代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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM