私の理解が正しければ、基本的に、コンパイラーがジェネリック型の 1 つを他の型から推測することを望んでいます。静的なジェネリック構築メソッドを使用することで、ある程度の距離を保つことができますが、妥協して、単一のジェネリック型パラメーターのみを使用して Watcher<T, TKey> にインターフェイスを実装させる必要があります。以下に説明を試みますが、妥協する価値があるかどうかを判断してください。
これが既存のウォッチャークラスです..
public class Watcher<T, TKey> : IWatcher<TKey> where T : IWatchable<TKey>
{
public Watcher(IWatchable<TKey> target) { }
}
実装する必要があるインターフェイスは次のとおりです。
public interface IWatcher<TKey> { }
ここで、型パラメーターを 1 つだけ必要とするジェネリック メソッドを含む、非ジェネリックな static Watcher クラスが必要になります。
public static class Watcher
{
public static IWatcher<TKey> For<TKey>(IWatchable<TKey> target)
{
return new Watcher<IWatchable<TKey>, TKey>(target);
}
}
型シグネチャは、Watcher<IWatchable<TKey>, TKey> を構築していますが、戻り値の型として IWatcher<TKey> を持っていることに注意してください。このトリックにより、型パラメーターを 1 つだけ指定できるようになります。
次のトリックは、"For" メソッドを呼び出すときに "TKey" 型を指定する必要がないように、C# の型推論に依存することです。クラスを受講した場合:
public class BeingWatched : IWatchable<int>
{
public BeingWatched(int key)
{
Key = key;
}
public int Key { get; }
}
次に、次のコードを使用して、このインスタンスのウォッチャーを取得できます。
var watcher = Watcher.For(new BeingWatched(123));
型推論により、明示的に記述する必要がなくなります
var watcher = Watcher.For<int>(new BeingWatched(123));
これは、あいまいさがない限り機能します。クラスがあれば
public class AlsoBeingWatched : IWatchable<int>, IWatchable<Guid>
{
private readonly int _numberKey;
private readonly Guid _guidKey;
public AlsoBeingWatched(int numberKey, Guid guidKey)
{
_numberKey = numberKey;
_guidKey = guidKey;
}
int IWatchable<int>.Key { get { return _numberKey; } }
Guid IWatchable<Guid>.Key { get { return _guidKey; } }
}
それから
var watcher = Watcher.For(new AlsoBeingWatched(123, Guid.NewGuid()));
コンパイルされず、エラーが発生します
The type arguments for method 'Watcher.For<TKey>(IWatchable<TKey>)' cannot be inferred from the usage.
どちらかを明示的に指定する必要があります
var watcher = Watcher.For<int>(new AlsoBeingWatched(123, Guid.NewGuid()));
また
var watcher = Watcher.For<Guid>(new AlsoBeingWatched(123, Guid.NewGuid()));
このアプローチは、あなたが求めていたもの (またはおそらくあなたが望んでいたもの) とはまったく異なるかもしれませんが、多くの一般的なケースで型を明示的に指定する必要がないようにするための最良の方法だと思います.