泛型 IAbstract<T> 继承自 IAbstract。

10

我想实现类似于这样的效果:

interface IAbstract
{
    string A { get; }
    object B { get; }
}

interface IAbstract<T> : IAbstract
{
    T B { get; }
}

class RealThing<T> : IAbstract<T>
{
    public string A { get; private set; }
    public T B { get; private set; }
}

所以我可以像这样做:
RealThing<string> rt = new RealThing<string>();
IAbstract ia = rt;
IAbstract<string> ias = rt;
object o = ia.B;
string s = ias.B;

这个可能吗?

1
.NET框架中这种模式的一个很好的例子是IEnumerableIEnumerable<T>,其中IEnumerableIEnumerator GetEnumerator(),而IEnumerable<T>则使用IEnumerator<T> GetEnumerator()来完成与您的属性完全相同的操作。 - Scott Chamberlain
4个回答

10
几乎没错。有三点需要注意:

  • You should use new in IAbstract<T> to indicate that you know you're hiding an existing member:

    new T B { get; }
    

    But even without that, you'll still only get a warning.

  • You need to implement the IAbstract.B within RealThing, which you should almost certainly do using explicit interface implementation, delegating to the strongly-typed member:

    object IAbstract.B { get { return B; } }
    
  • Within your test code, you need to specify a type argument for RealThing:

    RealThing<string> rt = new RealThing<string>();
    

这很好,并且在需要获得接口的非泛型形式时是一个相当常见的模式。


7
是的,需要进行一些小的更改。
interface IAbstract
{
    string A { get; }
    object B { get; }
}

interface IAbstract<T> : IAbstract
{
    new T B { get; }
}

sealed class RealThing<T> : IAbstract<T>
{
    public string A { get; private set; }
    public T B { get; private set; }

    object IAbstract.B
    {
        get { return B; }
    }
}

因此,您可以编写

var rt = new RealThing<string>();
IAbstract ia = rt;
IAbstract<string> ias = rt;
object o = ia.B;
string s = ias.B;

1
IAbstract<T> 上的 B 属性是否应该标记为 new 关键字,以使遮蔽变得明确? - O. R. Mapper

1
实际上,System.Collections.IEnumeratorSystem.Collections.IEnumerator<T> 接口可以实现这一点。当你实现 IEnumerable<T> 时,你将不得不显式地实现其中一个 Current 属性,通常你会选择非泛型属性:
object IEnumerable.Current
{
    // this calls the implicitly implemented generic property
    get { return this.Current; }
}

public T Current
{
    get { return this.current; } // or however you want to do it
}

1
在这种情况下,您甚至不需要两个接口。只需将接口标记为协变(自 C# 4 起支持):
interface IAbstract<out T>
{
    string A { get; }
    T B { get; }
}

并且在之前使用非泛型接口的地方,使用IAbstract<object>


谢谢。我的使用情况是我需要将其用作参数化类型。我认为List<IAbstract>是更好的方式。 - Cheetah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接