在重写模板方法时访问中间类属性
本文关键字:中间 属性 访问 重写 模板方法 | 更新日期: 2023-09-27 17:57:57
我有一个抽象类,GenericModel
,它定义了一个模板方法,如下所示:
public virtual string DoStuff<TType>(IEnumerable<TType> input)
where TType : GenericModel { return null; }
然后,我有一个继承自GenericModel
的类,称为BasicModel
,它表示GenericModel
的某个子集,这些子集有足够的共同点来保证另一种结构。虽然这是一个具体的类,但它从未真正实例化,而是其他类从它继承,因为有许多共同的属性不一定在每个GenericModel
中,而是在每个BasicModel
中(例如,我们会说每个BasicModel
都有一个id
属性(。
如果我有一个继承自BasicModel
的类,称为 ChildModel
,并且我想覆盖DoStuff()
,这是允许的,因为ChildModel
继承自从GenericModel
继承BasicModel
。所以我定义了一个覆盖方法(在ChildModel
中(,如下所示:
public override string DoStuff<ChildModel>(IEnumerable<ChildModel> input){
foreach(var data in input){
var foo = data.id;
//Do stuff with foo
}
//Do more stuff
}
问题是Visual Studio将data.id
突出显示为错误,说data
没有名为id
的属性。我的假设是,这是由于模板方法的where TType : GenericModel
部分;它忽略了中间BasicModel
,因此我无法访问BasicModel
中定义的属性。
这对我来说似乎很奇怪,因为我说输入必须由 ChildModel
组成,根据定义,作为 BasicModel
的子类,它们都具有id
属性。
有没有办法在ChildModel
的覆盖中访问这些中间类属性DoStuff()
或者我设置继承的方式是不可能的?我可以进行任何解决方法或更改以允许使用这些属性吗?
编辑:从评论和答案来看,我对模板方法有根本的误解。我真正想做的是在GenericModel
中定义一个泛型方法,该方法将IEnumerable<GenericModel>
作为输入,然后在每个子类中被重写,其中覆盖使用IEnumerable<ChildClass>
代替。显然,以我定义的结构,这个目标可能是不可能的。
public override string DoStuff<ChildModel>(IEnumerable<ChildModel> input) { ... }
不是专门DoStuff
只使用ChildModel
,而只是将TType
参数重命名为ChildModel
。这相当于
public override string DoStuff<T>(IEnumerable<T> input) { }
这不会编译,因为您还需要保留基类中对TType
的约束。
DoStuff
方法的一般约束意味着覆盖必须统一处理所有子类型。听起来您希望每个子类都支持GenericModel
的单个特定子类型。 在这种情况下,您可以将泛型参数移动到基类中,并在每个子类中指定它,例如
public abstract class BaseClass<TType> where TType : GenericModel {
public virtual string DoStuff(IEnumerable<TType> input) { ... }
}
public class SubClass : BaseClass<ChildModel> {
public override string DoStuff(IEnumerable<ChildModel> input) { ... }
}
如果你不想要CastException(@Fabjan答案(,你可以替换它:
var castedInput = input.Cast<BasicModel>();
foreach (var data in castedInput)
有了这个:
foreach (var data in input.OfType<BasicModel>())
这样,如果您有此示例:
new ChildModel().DoStuff(new List<GenericModel>
{
new GenericModel(),
new BasicModel{id = 2},
new ChildModel{id = 10},
new BasicModel{id = 15}
});
像这样做东西:
var foo = data.id;
Console.WriteLine(foo);
您的输出将是:
2
10
15
好吧,使用当前逻辑ChildModel
类型参数只能是 GenericModel
类型,因为不可能覆盖泛型类型约束。正因为如此 - 编译器无法知道我们实际上传递了一些可转换为BasicModel
的东西,这就是为什么我们看不到属性 'id' 的原因。
要将其用作BasicModel
我们可以使用以下LINQ
铸造整个集合:
class GenericModel
{
public virtual string DoStuff<TType>(IEnumerable<TType> input)
where TType : GenericModel
{
return null;
}
}
class BasicModel : GenericModel
{
public int id { get; set; }
}
class ChildModel : BasicModel
{
public override string DoStuff<TType>(IEnumerable<TType> input)
{
var castedInput = input.Cast<BasicModel>();
foreach (var data in castedInput)
{
var foo = data.id;
//Do stuff with foo
}
//Do more stuff
return null;
}
}