【问题标题】:Generics: The type 'Camera' cannot be used as type parameter 'T' in the generic type泛型:“相机”类型不能用作泛型类型中的类型参数“T”
【发布时间】:2015-02-18 12:03:46
【问题描述】:
interface IResourceProperties
{
}

class TopLevelResource<T> 
where T: IResourceProperties
{

}

class Camera: TopLevelResource<CameraProperties>
{
}

class CameraProperties : IResourceProperties
{
}

class Phone: TopLevelResource<PhoneProperties>
{
}

class PhoneProperties : IResourceProperties
{
}

void Main()
{
 List<Camera> cameras = new List<Camera>();
 List<Phone> phones = new List<Phone>();
 DoSomething(cameras);
 DoSomething(phones);
}

void DoSomething<T>(List<T> items)
where T: TopLevelResource<IResourceProperties>
{
  return;
}

我有上面提到的类层次结构。 通用方法DoSomething 需要能够在相机和电话上工作。 但我收到以下错误:

类型“Camera”不能用作泛型中的类型参数“T” 类型或方法“DoSomething(System.Collections.Generic.List)”。 没有从“服务器”到的隐式引用转换 'TopLevelResource'。

这表明这是不可能的。

能够通用地编写 DoSomething 并同时处理电话和相机的最佳选择是什么。

【问题讨论】:

  • Server 类型从何而来?您在编译或运行时是否收到此错误?这是您尝试调用 DoSomething 方法的时候吗?
  • 我忽略了 Server 错误作为红鲱鱼 - 假设发布的代码是对实际使用代码的简化。
  • 已修复。它实际上是相机而不是服务器

标签: c# generics


【解决方案1】:

您遇到的问题是TopLevelResource 不起作用covariantly,即TopLevelResource&lt;PhoneProperties&gt; 不是TopLevelResource&lt;IResourceProperties&gt;

您可以通过使用PhoneCamera 派生自的IDevice 接口来解决此问题:

interface IDevice&lt;out T&gt; where T : IResourceProperties

注意IDevice&lt;out T&gt; 所以它是variant generic interface

另一个具有&lt;out T&gt; 的接口的示例是IEnumerable&lt;out T&gt;。如果TDerived : TBase,那么IEnumerable&lt;TDerived&gt; 也是IEnumerable&lt;TBase&gt;IEnumerable&lt;object&gt;

您的代码将是:

interface IResourceProperties
{ }

interface IDevice<out T>
    where T : IResourceProperties
{ }

class TopLevelResource<T> : IDevice<T>
    where T : IResourceProperties
{ }

class Camera : TopLevelResource<CameraProperties>
{ }

class Phone : TopLevelResource<PhoneProperties>
{ }

class CameraProperties : IResourceProperties
{ }

class PhoneProperties : IResourceProperties
{ }

internal class Runner
{
    public static void Run()
    {
        List<Camera> cameras = new List<Camera>();
        List<Phone> phones = new List<Phone>();
        DoSomething(cameras);
        DoSomething(phones);
    }

    static void DoSomething<T>(List<T> items)
        where T : IDevice<IResourceProperties>
    {
        return;
    }
}

【讨论】:

    【解决方案2】:

    或者在Phone和Camera中实现IResourceProperties

    interface IResourceProperties
    {
    }
    
    class TopLevelResource<T> 
    where T: IResourceProperties
    {
    
    }
    
    class Camera: TopLevelResource<CameraProperties>, IResourceProperties
    {
    }
    
    class CameraProperties : IResourceProperties
    {
    }
    
    class Phone: TopLevelResource<PhoneProperties>, IResourceProperties
    {
    }
    
    class PhoneProperties : IResourceProperties
    {
    }
    
    
    
        class Program
        {static void DoSomething<T>
            (List<T> items) where T : IResourceProperties
        {
      return;
    }
            static void Main(string[] args)
            {
                 List<Camera> cameras = new List<Camera>();
     List<Phone> phones = new List<Phone>();
     DoSomething(cameras);
     DoSomething(phones);
            }
    

    希望这会有所帮助。

    【讨论】:

    • 但现在 both PhonePhoneProperties 都实现了 IResourceProperties。虽然接口里面没有任何东西,没关系,但是一旦有一些实现,这将不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多