Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在单个数组中实现通用接口的多个类_C#_Generics_Covariance - Fatal编程技术网

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

C# 在单个数组中实现通用接口的多个类,c#,generics,covariance,C#,Generics,Covariance,假设我有一个泛型接口,该接口存储由泛型参数键入的值: public interface IFoo<TValue> { TValue SomeValue { get; set; } } 我现在决定要一个数组,它可以包含StringFoos和DoubleFoos: var foos = IFoo<object>[] { new StringFoo { SomeValue = "a value" }, new DoubleFoo { SomeValue

假设我有一个泛型接口,该接口存储由泛型参数键入的值:

public interface IFoo<TValue>
{
    TValue SomeValue { get; set; }
}
我现在决定要一个数组,它可以包含
StringFoo
s和
DoubleFoo
s:

var foos = IFoo<object>[] {
    new StringFoo { SomeValue = "a value" },
    new DoubleFoo { SomeValue = 123456789 }
}
但是,由于接口同时包含setter和getter,所以我不能这样做


因此,两个类可以在一个数组中实现一个通用接口吗?

这个问题可以通过实现Bar类的方式来解决(也提供了一个坏例子)。问题是,每当试图使用泛型接口或实现泛型接口的类时,代码可能会编译(提供正确的强制转换),但代码会在运行时抛出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>()
         };
    }
}

List和T[]的可能副本是完全不同的构造,它们显然可以从一个转换到另一个,但可能显示非常不同的行为,这取决于未来的语言设计决策及其底层运行时实现。这就是为什么这些问题是完全不同的。从语言理论的角度来看,今天的答案相似或相同的事实并不重要。如果没有使用抽象类,那么我们实际上就不能在这里被要求。@jacek是否可以不强制转换为
IFoo
?没有它,代码看起来会更干净(而且写起来会更短)。@jacek还有,当我尝试使用强制转换时,VS告诉我“可疑强制转换:解决方案中没有从StringFoo和IFoo继承的类型”编辑,我刚刚意识到
Bar
用于非强制转换。。。对…@RJ,若抽象类是你们想要避免的东西,那个么用接口替换它——否则就并没有办法从公共基中逃脱type@JacekBlaszczynski知道了。谢谢
public interface IFoo<out TValue>
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>()
         };
    }
}
public class GenericsInArrayTests
{
    [Fact]
    public void QuestionArrayTest()
    {
        Verify.QuestionArray();
    }

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

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