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