C# 使用构造的返回类型重写泛型基类属性

C# 使用构造的返回类型重写泛型基类属性,c#,oop,unity3d,generics,C#,Oop,Unity3d,Generics,我想在Unity编辑器中使用泛型类型定义,但无法(目前)更新到Unity 2020.1,它本机支持这一点。解决方法是定义扩展泛型类的非泛型类。 但是,当我试图用定义的类(基本上是泛型属性的命名版本)重写基类属性时,编译器报告这两种类型不兼容。因为这个描述非常。。。通用的下面是一些代码来说明我的问题: 类属性{} 类基类 { 公共虚拟财产属性{protected get;set;} } 类StringProperty:属性{} 类子类:基类 { 公共重写StringProperty属性{prote

我想在Unity编辑器中使用泛型类型定义,但无法(目前)更新到Unity 2020.1,它本机支持这一点。解决方法是定义扩展泛型类的非泛型类。 但是,当我试图用定义的类(基本上是泛型属性的命名版本)重写基类属性时,编译器报告这两种类型不兼容。因为这个描述非常。。。通用的下面是一些代码来说明我的问题:

类属性{}
类基类
{
公共虚拟财产属性{protected get;set;}
}
类StringProperty:属性{}
类子类:基类
{
公共重写StringProperty属性{protected get;set;}
}
SubClass.Property”:类型必须为“Property”才能与重写的成员“BaseClass.Property”匹配

SubClass.Property基本上是
Property
,但我不知道如何将其传达给编译器。

不支持协变返回类型。我相信它加了C#9

这意味着您不能更改被重写方法的返回类型。即使重写的方法返回派生类型

类似的内容无效:

class Animal
{

}

class Cat : Animal
{

}

abstract class AnimalFactory
{
    public abstract Animal CreateAnimal();
}

class CatFactory : AnimalFactory
{
    public override Cat CreateAnimal(); // Syntax error
}

尽管我们返回的是一个
Animal
(一个
Cat
是一个
Animal
),但它会给出一个编译器错误。

问题是,虽然每个
StringProperty
都是
属性,但不是每个
属性都是
StringProperty
。听起来怪怪的?我们开始吧

假设您的类的客户机具有以下功能:

BaseClass<string> b = new SubClass();
其中
MyProperty
还派生自
Property
。但是,这与您的期望相矛盾,
子类的实例具有
StringProperty
,而不是
MyProperty


这与泛型无关。简而言之,您不能通过覆盖成员的签名来更改其签名。基类和派生类成员都必须具有完全相同的签名,包括返回类型。

@HimBromBeere完美地解释了代码无法编译的原因,但有一个解决方法,尽管稍微详细一些

让您的基地接受
属性的类型,而不仅仅是
T

class BaseClass<TProperty, T> where TProperty : Property<T>
{
    public virtual TProperty Property { protected get; set; }
}
class基类,其中TProperty:Property
{
公共虚拟TProperty属性{protected get;set;}
}
现在您可以这样声明您的子类:

class SubClass : BaseClass<StringProperty, string> { }
class子类:基类{}
如果有多个子类需要
属性
,则可以在层次结构中引入另一个级别:

class SubClassString<TProperty> : BaseClass<TProperty, string> where TProperty : Property<string>
{ }
class子类字符串:基类,其中TProperty:Property
{ }
现在可以更简洁地声明子类:

class SubClass : SubClassString<StringProperty> { }
类子类:子类字符串{}

这不仅仅与退货类型有关<代码>属性
有一个setter,因此永远不能(安全地)协变。@JohnathanBarclay Visual Studio给了我一个错误:
在重写属性时不能更改返回类型。
我得到了“SubClass.Property”:类型必须是“Property”才能匹配被重写的成员“BaseClass.Property”。返回类型只是一个问题。我想它基本上可以归结为这个问题。虽然StringProperty可以被视为
属性
,但并非每个
属性
都可以被视为
StringProperty
。我希望c#有一些“声明”魔法(这显然不是继承),我可以说“这基本上就是这个,但有一个名字”。有趣的解决方案!是
T属性{protected get;set;}
还是
T属性{protected get;set;}
BaseClass
中?@aleneum是的,它应该是
T属性
。虽然@HimBromBeere的回答从技术上来说是我不想做的事情的最恰当解释,这个答案为我的基本问题提出了解决方案:通过传递
StringProperty
并将
Property
转换为一个变量,例如
publictproperty属性它显示为Unity可序列化,因此在编辑器中可用(如可编辑)。
class SubClassString<TProperty> : BaseClass<TProperty, string> where TProperty : Property<string>
{ }
class SubClass : SubClassString<StringProperty> { }