选择接受 base 或 child class 作为参数的重载方法

Choose overloaded method that accepts base or child class as parameter

标题可能写得不好,因为我真的不知道如何描述我的问题。 我的问题如下所述。 我有两个 classes:

class BaseModel {
   public string Name {get; set;}
}
class ChildModel : BaseModel {
   public string ChildName {get; set;}
}

第三个 class 我保留上面的实例 classes:

class OverallModel {
   public IEnumerable<BaseModel> Models {get; set;}
}

现在我有两个方法:

public MappedBaseModel MapModel(BaseModel source){
    var result = new MappedBaseModel();
    // do magic for basemodel
}
public MappedBaseModel MapModel(ChildModel source){
    var result = new MappedChildModel(); // MappedChildModel is a child of MappedBaseModel
    // do magic for childmodel
}

现在,当我像那样遍历 Models 时:

var list = new List<MappedBaseModel>();
foreach(var model in overallModel.Models){
    list.Add(MapModel(model));
}

我很困惑,因为代码只调用 MapModel(BaseModel),从不调用 MapModel(ChildModel)。我做了一个变通方法来检查模型是否属于 ChildModel:

foreach ...
    if(model is ChildModel)
        list.Add(MapModel(model as ChildModel)); // thats just ugly..
    else
        list.Add(MapModel(model));

我的问题是它看起来很糟糕。我不想检查模型的类型只是为了调用其他重载方法。 你能帮我让它更优雅吗? 我知道我可能没有提供足够的信息。请,如果您需要了解更多信息,请询问,我会尝试更深入地解释。 另外,对不起我的英语! 祝你有个愉快的一天。

这类问题通常可以使用 multiple dispatch 解决,但在您的场景中这可能有点矫枉过正。考虑将单个虚拟 Map() 方法添加到 BaseModel class:

class BaseModel {
    public virtual MappedModelBase Map() {
        var result = new MappedBaseModel();
        // ...
        return result;
    }
}

class ChildModel : BaseModel {
    public override MappedModelBase Map() {
        var result = new MappedChildModel();
        // ...
        return result;
    }
}

然后就是:

var list = new List<MappedBaseModel>();
foreach(var model in overallModel.Models)
    list.Add(model.Map());

现在,如果您喜欢 "enterprisey" 东西,这里是执行这种双重调度样式的方法:

public class Mapper
{
    public MappedBaseModel MapModel(BaseModel source);
    public MappedBaseModel MapModel(ChildModel source);
}

class BaseModel 
{
    public virtual MappedBaseModel MapWith(Mapper mapper)
    {
        return mapper.MapModel(this);
    }
}

class ChildModel : BaseModel 
{
    public override MappedBaseModel MapWith(Mapper mapper)
    {
        return mapper.MapModel(this);
    }
}

var mapper = new Mapper();
foreach(var model in overallModel.Models)
    list.Add(model.MapWith(mapper));

方法 MapModel(或其他某个方法)应该被覆盖,在这种情况下不应重载。

by Anton Gogolev 是上述场景应该采用的...


另一种方法是使用 dynamic 类型。你可以简单地做:

list.Add(MapModel((dynamic)model));

它会调用相应的重载。