4

私は常に、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;
    }
}

なぜこれが起こっているのか、その場合に型推論を機能させる方法についてのアイデアはありますか?

ありがとう。

4

2 に答える 2

3

のインターフェイス シグネチャはpublish、2 つの制約を定義します。

void Publish<TEvent, TPayload>(TEvent @event) where TEvent : IEvent<TPayload>;
  1. TEventメソッドパラメータの署名になります
  2. TPayloadどの州TEventがインターフェースを実装する必要があるかIEvent<TPayload>

Publish メソッドに の制約しかない場合、メソッドTEventのシグネチャには型制約が既に定義されているため、コンパイラは使用法を推測できます。つまり、

void Publish<TEvent>(TEvent @event);

上記により、メソッド呼び出しを型制約なしで使用できるようになります。つまり、

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

TPayloadただし、インターフェイスは 2 番目の制約を定義するため、イベントは任意の数の を実装できるため、コンパイラは意図が何であるかを認識できませんIEvent<TPayload>。ただし、メソッド シグネチャに の型が含まれていた場合TPayload、コンパイラは実際に制約を推測できます。つまり、

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

次に、型制約なしでメソッドを呼び出すことができます。

messageBus.Publish( new CorrectorAdded( 10 ), new FooThatImplementsTPayload() );
于 2013-11-09T20:29:42.203 に答える
0

代替 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();
}
于 2013-11-10T10:11:05.980 に答える