在单个数组中实现通用接口的多个 类

Multiple classes that implement a generic interface in a single array

假设我有一个通用接口,它存储一个由通用参数键入的值:

public interface IFoo<TValue>
{
    TValue SomeValue { get; set; }
}

然后我有两个类、StringFooDoubleFoo,它们的SomeValues分别是stringdouble

public class StringFoo : IFoo<string>
{
    string SomeValue { get; set; }
}

public class DoubleFoo : IFoo<double>
{
    double SomeValue { get; set; }
}

我现在决定我想要一个可以同时包含 StringFoos 和 DoubleFoos 的数组:

var foos = IFoo<object>[] {
    new StringFoo { SomeValue = "a value" },
    new DoubleFoo { SomeValue = 123456789 }
}

我认为,因为 stringdouble 都是 object 的子 类,所以它们都可以出现在这个数组中。然而,我想错了。

所以,我尝试使用协方差:

public interface IFoo<out TValue>

但是,由于接口同时包含 setter 和 getter,我不能这样做。

那么,两个 类 可以在一个数组中实现通用接口吗

问题可以通过实施 Bar class 的方式解决(也提供了错误的示例)。问题在于,无论何时尝试使用通用接口或 class 实现通用接口代码都可以编译(提供正确的强制转换),但代码将在 运行 时间内抛出 InvalidCastException。

public interface IFoo<TValue>
{
    TValue SomeValue { get; set; }
}

public class StringFoo : IFoo<string>
{
    public string SomeValue { get; set; }
}

public class DoubleFoo : IFoo<double>
{
    public double SomeValue { get; set; }
}

public class Foo<TValue> : IFoo<TValue>
{
    public TValue SomeValue { get; set; }
}

public abstract class Bar
{

}

public class Bar<TValue> : Bar, IFoo<TValue>
{
    public TValue SomeValue { get; set; }
}

public static class Verify
{
    public static void QuestionArray()
    {
        var foos = new IFoo<object>[]
        {
            (IFoo<object>) new StringFoo { SomeValue = "a value" },
            (IFoo<object>) new DoubleFoo { SomeValue = 123456789 }
        };
    }

    public static void BadAnswerArray()
    {
        var foo = new IFoo<object>[]
        {
            (IFoo<object>) new Foo<string>(),
            new Foo<object>(),
        };
    }

    public static void GoodAnswer()
    {
        var foo = new Bar[]
         {
            new Bar<string>(),
            new Bar<object>(),
            new Bar<double>()
         };
    }
}

为了验证解决方案,可以 运行 测试只有 GoodAnswerTest 会通过:

public class GenericsInArrayTests
{
    [Fact]
    public void QuestionArrayTest()
    {
        Verify.QuestionArray();
    }

    [Fact]
    public void BadAnswerTest()
    {
        Verify.BadAnswerArray();
    }

    [Fact]
    public void GoodAnswerTest()
    {
        Verify.GoodAnswer();
    }
}