[英]Accessing intermediate class properties in override of template method
我有一个抽象类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
继承自BasicModel
,而BasicModel
继承自GenericModel
。 所以我定义了一个重写方法(在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
的属性。 我的假设是这归因于template方法的where TType : GenericModel
部分; 它忽略了中间的BasicModel
,因此我无法访问BasicModel
定义的BasicModel
。
这对我来说似乎很奇怪,因为我要说输入必须由ChildModel
组成,根据定义,所有这些都将作为id
的BasicModel
子类。
有没有一种方法可以在ChildModel
的DoStuff()
重写中访问这些中间类属性,或者用我设置继承的方式是不可能的吗? 我可以进行任何变通办法或更改以允许使用这些属性吗?
编辑:从评论和答案看来,我对模板方法有基本的误解。 我真正想做的是在GenericModel
中定义一个通用方法,该方法以IEnumerable<GenericModel>
作为输入,然后在每个子类中都将其重写,其中重写使用IEnumerable<ChildClass>
代替。 显然,使用我定义的结构可能无法实现该目标。
public override string DoStuff<ChildModel>(IEnumerable<ChildModel> input) { ... }
并不是专门让DoStuff
仅与ChildModel
一起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) { ... }
}
好吧,使用当前逻辑, ChildModel
类型参数只能是GenericModel
类型,因为不可能覆盖泛型类型约束。 因此,编译器无法知道我们实际上传递了可转换为BasicModel
,这就是为什么我们看不到属性'id'的原因。
要将其用作BasicModel
我们可以使用LINQ
BasicModel
整个集合:
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;
}
}
如果您不想要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}
});
使用DoStuff像这样:
var foo = data.id;
Console.WriteLine(foo);
您的输出将是:
2
10
15
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.