避免显式泛型类型c#

时间:2016-08-31 07:34:29

标签: c# generics generic-constraints

假设我的通用classT必须实现IWatchable<TKey>的约束,有没有办法使用Watcher而无需明确声明TKey类型,考虑到T无论如何会提供此类型?

public class Watcher<T, TKey> where T : IWatchable<TKey>
{
}

public interface IWatchable<TKey>
{
    TKey Key { get; }
}

如果我想使用Watcher class,我必须将TKey声明为第二种类型。

var watcher = new Watcher<BeingWatched, int>();

public class BeingWatched : IWatchable<int> { ... }

或者

var watcher = new Watcher<AlsoBeingWatched<Guid>, Guid>();

public class AlsoBeingWatched<TKey> : IWatchable<TKey> { ... }

1 个答案:

答案 0 :(得分:2)

如果我理解正确,你基本上希望编译器从另一个推断出一种泛型类型。您可以通过使用静态通用构造方法获得一些距离,但您必须妥协并制作Watcher&lt; T,TKey&gt;实现只有一个泛型类型参数的接口。我将尝试在下面进行说明,您可以决定是否值得做出妥协。

这是您现有的Watcher课程。

public class Watcher<T, TKey> : IWatcher<TKey> where T : IWatchable<TKey>
{
    public Watcher(IWatchable<TKey> target) { }
}

以及它需要实现的界面:

public interface IWatcher<TKey> { }

现在我们需要一个非通用的静态Watcher类,它将包含一个只需要一个类型参数的泛型方法:

public static class Watcher
{
    public static IWatcher<TKey> For<TKey>(IWatchable<TKey> target)
    {
        return new Watcher<IWatchable<TKey>, TKey>(target);
    }
}

请注意,类型签名包含IWatcher&lt; TKey&gt;作为返回类型,即使它构建了Watcher&lt; IWatchable&lt; TKey&gt;,TKey&gt;。这个技巧允许我们只指定一个类型参数。

接下来的技巧是依靠C#的类型推断,这样我们就不必指定&#34; TKey&#34;在调用&#34; For&#34;时键入方法。如果我们上课:

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()));

这种方法可能不是您要求的(或者您希望的那样),但我认为这是避免必须为许多常见情况明确指定类型的最佳方法。