带有泛型参数的普通c#类将无缘无故地无法编译

本文关键字:无缘无故 编译 泛型 参数 | 更新日期: 2023-09-27 18:04:49

我想要一个泛型函数,可以与具有Top, Bottom, RightRect只读属性的类型一起工作-我在第三方库中有很多这样的类。

我写的是:

internal class MyTemplate<WhatType> {
    internal static void Work( WhatType what )
    {
        int left = what.Left;
    }
};

,我希望它能工作-在c++中等效的代码也可以工作。但是c#对象:

错误CS1061: 'WhatType'不包含'Left'的定义,并且没有扩展方法'Left'接受类型'WhatType'的第一个参数可以找到(您是否缺少using指令或程序集引用?)

我不明白-为什么它会在我调用它之前尝试实例化模板?当然,类型WhatType还不知道,所以没有找到任何属性。

我做错了什么,我如何解决这个问题?

带有泛型参数的普通c#类将无缘无故地无法编译

c#泛型不是模板;它们是在运行时提供的,而不是由编译器提供的。因此,没有鸭子打字。两个选择:

  • 使用where WhatType : ISomeInterface约束,其中ISomeInterfaceLeft {get;}
  • 使用dynamic(提供duck-typing)

internal class MyTemplate<WhatType> where WhatType : ISomeInterface {
    internal static void Work( WhatType what )
    {
        int left = what.Left;
    }
};
interface ISomeInterface {
    int Left { get; }
}

或:

internal class MyTemplate<WhatType> {
    internal static void Work( WhatType what )
    {
        int left = ((dynamic)what).Left;
    }
};

c#泛型看起来类似于c++模板,但实际上它们有很大的不同。c#泛型是强类型的,所以你不能调用非静态已知的成员。

为了能够在WhatType类型的对象上调用Left,您必须使用泛型约束指定WhatType实现接口或继承定义Left的类。例如:

interface IHasPosition
{
    int Left { get; }
    int Top { get; }
}
internal class MyTemplate<WhatType> where WhatType : IHasPosition
{
    internal static void Work( WhatType what )
    {
        int left = what.Left;
    }
};

您可以这样指定类型:

internal class MyTemplate<WhatType> where WhatType : LeftInterface

那么你可以使用.Left调用。

LeftInterface可能看起来像这样:

public interface LeftInterface
{   
   int Left {get; set;}
}

泛型用于类型安全。现在,没有任何关于WhatType的额外信息,编译器如何知道传入的实例what将具有Left属性?

你需要这样的东西

public interface IFoo
{
    int Left {get;}
}

internal class MyTemplate<WhatType> where WhatType : IFoo {

必须在where子句中指定支持。left的基类,或者必须将what强制转换为支持。left -property的类型:

internal class MyTemplate<WhatType> where WhatType : YourBaseClassWithLeftProperty

internal class MyTemplate<WhatType> {
  internal static void Work( WhatType what )    {        
    YourBaseClassWithLeftProperty yourInstance=what as YourBaseClassWithLeftProperty;
    if(null != yourInstance){
         int left = yourInstance.Left;    
    }
  }
  ...

嘿,男孩,你只是需要这个:

强制在c#中实现泛型接口

这样你就可以假设你的WhatType实例将有Left, Bottom等等…

您没有为WhatType类型指定任何条件,因此它将接受任何类型,并且只知道每种类型所知道的,即只知道Object类中定义的内容。

如果你想在类型中使用其他任何东西,你必须指定它包含什么,你可以通过指定它必须实现一个接口或继承一个类来实现:

internal class MyTemplate<WhatType> where WhatType : BaseType {

其中BaseType可能是定义了Left属性的接口或类