C#Generic Interfaces转换问题

时间:2012-01-26 19:49:17

标签: c# .net generics

使用c#4和VS 2010是否可以实现?我正在对实现通用接口的类进行一些处理,并且在处理之后想要将对象转换为更简单的接口,以便我可以提取由公共接口定义的某些属性。

interface IMyInterface
{
    public Id { get; set; }
}

interface IFile<T1, T2> where T1 : IMyInterface where T2 : IMyInterface
{
    Int64 prop1 { get; set; }
    T1 t1 { get; set; }
    T2 t2 { get; set; }
}

ClassA : IMyInterface
{
    ... Implement some properties plus interface
    public Id { get; set; }
}

ClassB : IMyInterface
{
    ... Implement some properties plus interface
    public Id { get; set; }
}

例如,这个类有ClassX和ClassY我想成为处理/保存的某些类型,但之后我只想提取像ID一样的常见属性,这在实现这个通用接口的所有类中很常见(其他属性)在t1,t1中不常见

ClassSomething : IFile<ClassA, ClassB>
{
    ... Implement properties plus interface 
    public ClassX t1 
    { get {}   set {} }
    public ClassY t2 
    { get {}   set {} }
}



IList<IFile<TItem1, TItem2>> list = new List<IFile<TItem1, TItem2>>() 
    ClassA ca = new ClassA();
    ... Fill in the interface defined properties
    ... Fill the list with objects of ClassSomething

foreach (IFile<TItem1, TItem2> x in list)
{
    // This fails
    IFile<IMyInterface, IMyInterface> interfaceItem = 
        (IFile<IMyInterface, IMyInterface>)x;
}

x以上(t1t2属性专门针对)更简单的IMyInterface接口转换为失败。

有很多通用界面问题,但我没有看到(或认出?)任何解决方案。

4 个答案:

答案 0 :(得分:5)

您正在寻找的解决方案称为variance(协方差和逆变)。但是,IMyInterfaceT1中的T2无法提供协变或逆变,因为它有公共getter和公共setter接受T1T2:< / p>

interface IAnimal {}
class Dog : IAnimal { public void Bark () ; }
class Cat : IAnimal { public void Meow () ; }

var dogs = new FileImpl<Dog, Dog> () ;
dogs.t1  = new Dog () ;

var file = (IFile<IAnimal, IAnimal>) dogs ; // if this were OK...
file.t1  = new Cat () ;                     // this would have to work
dogs.t1.Bark () ;                           // oops, t1 is a cat now

答案 1 :(得分:2)

只是为了扩展Anton Tykhyy的回答,

是的,如果您愿意/能够对您的IFile界面进行以下更改,您可以使用C#4实现此目的:

interface IFile<out T1, out T2> where T1 : IMyInterface where T2 : IMyInterface
{
    Int64 prop1 { get; set; }
    T1 t1 { get; }
    T2 t2 { get; }
}

我已将out关键字添加到通用参数中,并且我已从t1和t2属性中删除了set;

答案 2 :(得分:1)

为什么不访问x.T1x.T2,然后将其转换为IMyInterface

foreach (IFile<TItem1, TItem2> x in list)
{
   var t1 = x.T1 as IMyInterface;
   var t2 = x.T2 as IMyInterface;
}

答案 3 :(得分:1)

我认为你将通用约束与继承混淆了。一个与另一个无关。泛型接口的约束是编译器指令,它告诉编译器泛型参数必须满足特定的要求。从逻辑上讲,对我们来说,这意味着ClassSomething肯定有IMyInterface的实现。但这就是我们,编译器不会将这些约束转换为任何类型的继承映射,因此它仍然只知道它是实现ClassSomething的{​​{1}}实例。因此,它不会让您直接将其转换为IFile<ClassA, ClassB>