【问题标题】:Choose overloaded method that accepts base or child class as parameter选择接受基类或子类作为参数的重载方法
【发布时间】:2016-08-05 13:26:48
【问题描述】:

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

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

以及我保留上述类实例的第三类:

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));

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

【问题讨论】:

  • 或者使用dynamic关键字list.Add(MapModel((dynamic)model));
  • 什么是MappedBaseModel?你在哪里定义的?

标签: c# .net inheritance overloading


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    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());
    

    现在,如果你喜欢“企业”的东西,这里是如何做到这种双重派送风格:

    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));
    

    【讨论】:

    • 不错且广泛的答案!缺点是从..ModelMappedBaseModel 的转换现在在以前的类中。在一个上下文中,例如BaseModel 是单独程序集中的域模型类,MappedBaseModel 是例如一个视图模型类,不希望让BaseModel 知道MappedBaseModel
    【解决方案3】:

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


    另一种方法是使用dynamic 类型。你可以这样做:

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

    它会调用相应的重载。

    【讨论】:

    • dynamic 无需重写大部分代码即可完成工作。绝妙的把戏,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2010-12-07
    • 2022-11-24
    • 1970-01-01
    • 2014-08-03
    • 2017-11-08
    相关资源
    最近更新 更多