【问题标题】:Interface with object List<IAnotherInterface> - Is this possible?与对象 List<IAnotherInterface> 的接口 - 这可能吗?
【发布时间】:2012-09-25 23:46:03
【问题描述】:

是否可以定义一个接口,其中一个对象是另一个接口的列表?

我有两个 EF 对象:

=====

class ImageType1
{
    string Id
    string Name
    List<ImageType1Size> Sizes
}

class ImageType1Size
{
    string Id
    int Width
    int Height
}

class ImageType2
{
    string UserId
    string ImageId
    string Name
    List<ImageType2Size> Sizes
}

class ImageType2Size
{
    string UserId
    string ImageId
    int Width
    int Height
}

=====

对于每个图像大小类,所有属性都是键(只是一个旁注)。

现在,我要做的是创建以下两个接口:

=====

interface IImage
{
    string Name
    List<ImageSize> Sizes
}

interface IImageSize
{
    int Width
    int Height
}

=====

在我的项目中,我为 ImageType1、ImageType1Size、ImageType2 和 ImageType2Size 创建了部分,每个都使用各自的接口。

我在尝试将 ImageType1 和 ImageType2 中的 Sizes 属性转换为使用接口 IImageSize 时遇到错误。

=====

这可能吗?如果我不清楚,请告诉我,我会重新提出问题。

谢谢!

【问题讨论】:

  • 您能否发布导致此错误的确切代码行。提供答案后会更容易表达清楚。

标签: c# interface


【解决方案1】:

由于 ImageType1 类的签名强制 ImageType1.Sizes 仅包含 ImageType1Size 对象,因此不允许在 ImageType1.Sizes 内存储 IImageSize,因为这将允许将非 ImageType1Size 对象(例如 ImageType2Size)添加到列表。

这意味着您不能将任何旧的 IImageSize 存储在 ImageType1.Sizes 中,这可能是您想要的。

您仍然可以在执行其他操作时仍然使用 ImageSize1 和 ImageSize2 对象,就像它们是 IImageSizes 一样,例如

void Test()
{
    ImageType2 image = new ImageType2();
...
    foreach(var size in image.Sizes)
    {
        if(IsTooBig(size))
        {
            MessageBox.Show("I'm too big!")l
        }
    }
}

bool IsTooBig(IImageSize imagesize)
{
    return imagesize.Width > 500;
}

现在您可以在 ImageType1Size 和 ImageType2Size 对象上使用 IsTooBig。

【讨论】:

    【解决方案2】:

    之前有一个关于将 List 转换为 List 的完整讨论。

    你可以在这里阅读它,但它的要点是你不能在 C# 中做到这一点。

    C# - Cannot implicitly convert type List<Product> to List<IProduct>

    【讨论】:

      【解决方案3】:

      foreach (IImageSize iSize in list) { int iWid = iSize.Width; }

      【讨论】:

        【解决方案4】:

        您可能想在这里考虑泛型:

        interface IImage<TSize> where TSize : IImageSize
        {
            List<TSize> Sizes { get; }
        }
        
        class ImageType1 : IImage<ImageType1Size>
        {
            List<ImageType1Size> Sizes { get; private set; }
        }
        

        或者,这也可以:

        interface IImage
        {
            IEnumerable<IImageSize> Sizes { get; }
        }
        
        class ImageType1
        {
            public List<ImageType1Size> SizeList { get; private set; }
        
            public IEnumerable<IImageSize> Sizes { get { return SizeList; } }
        }
        

        这取决于最适合您操作数据的方式。

        【讨论】:

        • 我最终选择了选项 2。谢谢!
        【解决方案5】:

        要建立在 default.kramer 所说的基础上,如果您明确需要 IImage 作为其他地方的类型,您可以像这样拆分接口:

        interface IImage
        {
          string Name
        }
        interface IImage<TSize> : IImage where TSize : IImageSize
        {
            List<TSize> Sizes { get; }
        }
        
        class ImageType1 : IImage<ImageType1Size>
        {
            List<ImageType1Size> Sizes { get; private set; }
        }
        

        如果不这样做,您将永远无法拥有一个裸露的IImage,而不指定它是TSize。当然,如果您需要能够访问非泛型 IImageSizes 属性,则需要添加如下扩展方法:

        static class IImageHelper
        {
          static List<IImageSize> GetSizes<TSize>(this IImage<TSize> image) where TSize: IImageSize
          {
            return image.Sizes.OfType<IImageSize>();
          }
        }
        

        【讨论】:

          【解决方案6】:

          很遗憾,这无法完成。在推理原因时,在界面之外考虑您的问题会很有帮助。

          public void Example()
          {
            List<ImageType1Size> Sizes1 = new List<ImageType1Size>();
            List<ImageType2Size> Sizes2 = new List<ImageType2Size>();
            List<IImageSize> Sizes;
          
            Sizes1 = Sizes; // These won't compile because the compiler can't guarantee that an
            Sizes2 = Sizes; // IImageSize is an ImageType1Size. It could be an ImageType2Size
          
            Sizes = Sizes1; // These will compile because the compiler knows that both 
            Sizes = Sizes2; // ImageType1Size and ImageType2Size are IImageSize's
          }
          

          现在您可以将其与您的课程进行比较。

          class ImageType1 : IImageType
          {
            string Id {get; set;}
            string Name {get; set;}
            List<ImageType1Size> Sizes {get; set;} // This is just like Sizes1 = Sizes in the
                                                   // example above.
          }
          
          public void Test(IImageSize imageSize)
          {
            IImageType imageType = new ImageType1();
          
            imageType.Add(imageSize) // This would compile, as IImageType.Sizes will 
                                     // take any IImageSize
          
            // But what really happens behind the interface is this:
            ((ImageType1)imageType)Sizes.Add(imageSize);    
          
            // Trying to insert an IImageSize into the collection
            // doesn't work, because the compiler can't guarantee that 
            // it's an ImageType1Size
          }
          

          注意:我假设您的示例显示

          interface IImage
          {
            string Name
            List<ImageSize> Sizes
          }
          

          实际上应该是

          interface IImage
          {
            string Name
            List<IImageSize> Sizes
          }
          

          因为您没有在其他地方提到“ImageSize”类型。

          【讨论】:

            猜你喜欢
            • 2011-07-31
            • 1970-01-01
            • 2019-11-02
            • 1970-01-01
            • 1970-01-01
            • 2018-10-21
            • 2011-04-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多