【问题标题】:Avoiding explicit generic type c#避免显式泛型类型 c#
【发布时间】:2016-08-31 07:34:28
【问题描述】:

假设我有一个通用的class 有一个约束,其中T 必须实现IWatchable<TKey>,有没有什么方法可以使用Watcher 而不必显式声明TKey 类型,考虑到@ 987654326@ 会提供那个吗?

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> { ... }

【问题讨论】:

  • 考虑类型系统将允许一个类型实现一个泛型接口多次次(使用不同的类型参数)。
  • @Damien_The_Unbeliever 所以如果BeingWatched 实现了IWatchable&lt;int&gt;IWatchable&lt;Guid&gt; 那么Watcher 将不知道在BeingWatched 中使用哪个实现?这就是为什么它需要明确。
  • where 子句仅用于约束检查 不用于类型解析...但是,您是否还需要知道Watcher 上的T?也许将观察者注册为public class Watcher&lt;TKey&gt; 并使用IWatchable 而不是具体类型就足够了?

标签: c# generics generic-constraints


【解决方案1】:

如果我理解正确,您实际上是希望编译器从另一个泛型类型中推断出其中一种。您可以通过使用静态泛型构造方法来实现这一点,但您必须妥协并让 Watcher 实现一个只有一个泛型类型参数的接口。我将尝试在下面进行说明,您可以决定是否值得做出妥协。

这是你现有的 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 作为返回类型,即使它正在构造 Watcher, TKey>。这个技巧允许我们只指定一个类型参数。

下一个技巧是依赖 C# 的类型推断,这样我们在调用“For”方法时就不必指定“TKey”类型。如果我们上过课:

public class BeingWatched : IWatchable<int>
{
    public BeingWatched(int key)
    {
        Key = key;
    }

    public int Key { get; }
}

然后我们可以使用以下代码获取 this 实例的观察者:

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

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

【讨论】:

  • 有趣的解决方法,这绝对看起来有点矫枉过正,但现在我明白了为什么必须明确声明类型。不过谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 2021-06-11
  • 1970-01-01
  • 2020-12-15
  • 2021-12-08
  • 2011-04-16
  • 1970-01-01
相关资源
最近更新 更多