【问题标题】:C# Generic Interfaces casting issueC# 通用接口转换问题
【发布时间】:2012-01-27 04:20:16
【问题描述】:

这应该可以使用 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 接口失败。

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

【问题讨论】:

  • 你可能需要看看c# 4.0 covariance and contravariance
  • 哇,答案又快又好看。我需要花一点时间消化答案。 :)
  • 很好的答案,他们都很有帮助,我会根据大众投票选择一个答案。 (我

标签: c# .net generics


【解决方案1】:

您正在寻找的解决方案称为variance(协变和逆变)。但是,您的 IMyInterface 不能在 T1T2 中成为协变或逆变,因为它有接受 T1T2 的公共 getter 和公共 setter:

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

【讨论】:

    【解决方案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;

    【讨论】:

    • 同意你的观点,如果可能的话,我也会应用协方差。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2020-09-25
        • 1970-01-01
        • 1970-01-01
        • 2012-09-04
        • 1970-01-01
        • 2011-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多