2017-10-15 82 views
1

说我有,其存储泛型参数输入值的通用接口:多个类

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

然后,我有两个班,StringFooDoubleFooSomeValuesstring S和double小号分别为:

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

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

我现在决定,我想,可以同时包含StringFoo S和数组个S:

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

我倒是觉得,因为这两个stringdoubleobject子类,他们都希望能在这个数组中允许的。但是,我认为是错误的。

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

public interface IFoo<out TValue> 

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

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

+3

的可能的复制[C# - 在一个列表中的多个泛型类型(https://stackoverflow.com/questions/353126/c-sharp-multiple-generic-types-in-one-list) – Fruchtzwerg

+0

列表和T []是完全不同的结构,显然可以从一个转换到另一个,但可能会根据未来的语言设计显示非常不同的行为决策及其基础运行时实现。这就是为什么这个问题完全不同。事实上,从语言理论的角度来看,今天的答案相似或相同并不重要。 –

回答

1

该问题可以通过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>() 
     }; 
    } 
} 

,并验证解决方案可以运行测试,其中只有GoodAnswerTest将通过:

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

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

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

如果没有抽象类的使用,那么我们在这里实际上可能不需要。 –

+0

@jacek有没有可能没有投到'IFoo '?没有它的代码看起来会更干净(并且写得更短)。 – Zoweb

+0

@jacek此外,当我尝试使用投射,VS告诉我“可疑的演员:没有类型的解决方案,这是继承自StringFoo和IFoo ” *编辑*而我刚刚意识到'酒吧'是为非铸造...正确... – Zoweb