【问题标题】:C# Assigning items from params to variables based on classC#根据类将参数从参数分配给变量
【发布时间】:2018-04-08 22:15:23
【问题描述】:

我有一个问题,我将具有不同类但相同父类的多个项目作为参数传递给类构造函数,然后将它们分配给新类的变量:

public class Tool {}
public class Hammer:Tool {}
public class Screwdriver:Tool{}

所以我的工具类都继承自父工具类。现在我想创建一个工具箱,用来存放我的工具;但是,我并不总是想用一整套工具来制作它,所以我传递了一个参数数量未定义的参数:

public class Toolbox{
public Hammer hammer;
public Screwdriver screwdriver;
public Toolbox(params Tool[] tool){
    foreach (Tool t in tool){
        switch (t.getType().Name){
            case "Hammer":
                hammer = t;
                break;
            case "Screwdriver":
                screwdriver = t;
                break;
        }
    }
}

这会导致编译器说它“无法将 'Tool' 隐式转换为 'Hammer',但可以进行显式转换”。 在这种情况下可能是什么问题,是否可以通过一些简单的方式解决?

【问题讨论】:

  • 虽然您可以像这样轻松地将 t 转换为 Hammer (Hammer)t,但您应该考虑更改 Toolbox 构造函数的参数列表。目前的设计听起来很糟糕。
  • 作为一个业余的 C#-er:为什么这是一个糟糕的设计?我需要将许多具有相同父类的对象传递给构造函数。有什么更好的方法?
  • 为什么需要区分它们?难道你不能只有一个工具列表,并且每个工具都有其以不同方式工作的 Use 方法吗?
  • 顺便说一句,如果你想让 Stilgar 看到你对他的评论的回答,你需要写 @HisName 这样他就会收到通知你回答了他的评论。
  • 我希望它们具有不同的参数,并且设计只能容纳特定类别工具的插槽。参数字典和名称参数区分会更好吗?

标签: c# class inheritance parameters


【解决方案1】:

当你大量使用case/switch时,你应该把它当作一个警告信号,表明你没有以OO方式做事。

执行此操作的 OO 方法是为 Tool 定义一个公共属性,并且仅在选择插槽时使用该属性。然后在后代类中设置位置,如下所示:

Enum Location { Big, Large, Small, Drawer, Hanging}

class Tool
{
    public abstract Location Location { get; }
}

class Hammer
{
    public override Location { get { return Location.Top; } }
}

现在您的工具箱代码很简单:

class Toolbox
{
    public readonly List<Location,List<Tool>> Store = new List<Location,List<Tool>>();

    public Toolbox(params Tool[] tool)
    {
        foreach (Tool t in tool)
            this.Store[t.Location].Add(t);
    }
}

如果你需要比这更复杂的,你可以把逻辑放到后代类中:

class Tool
{
    public abstract void StoreIn(Toolbox toolbox);
}

class Hammer
{
    public override void StoreIn(Toolbox toolbox)
    {
        toolbox.TopDrawer.Add(this);
    }
}

同样,您的工具箱代码很简单:

class Toolbox
{
    public void AddTools(params Tool[] tool)
    {
        foreach (Tool t in tool) t.StoreIn(this);
    }
}

【讨论】:

  • 好的,这看起来很不错,但是当这有点复杂时,我需要看看是否可以将其应用于我的情况。它看起来仍然比我做的要好。
【解决方案2】:

问题在于知道它是Hammer,但编译器只知道它是Tool。正如错误消息所说,解决这个问题的方法是通过显式转换:

hammer = (Hammer)t;

通过这个转换,你告诉编译器t 实际上是Hammer

【讨论】:

    【解决方案3】:

    你可以试试这个吗?此转换操作可以为您提供预期的结果。您可以访问和使用derived class 属性

    编辑答案并添加@ja72 推荐

    foreach (Tool t in tool)
    {
        // option 1
        if (t is Hammer)
        {
            Hammer hammer = t as Hammer;
            .....
        }
    
        // option 2 @ja72 recomendation
        if (t is Screwdriver screwdriver)
        {
            .......
        }
    }
    

    【讨论】:

    • 也可以使用C#模式匹配if(t is Hammer hammer) { this.hammer = hammer; }
    【解决方案4】:

    在现代 C# 中,这是检查类型的方式:

    public class Toolbox
    {
        readonly Hammer hammer;
        readonly Screwdriver screwdriver;
        public Toolbox(params Tool[] tool)
        {
            foreach (Tool t in tool)
            {
                if (t is Hammer hammer)
                {
                    this.hammer = hammer;
                }
                if (t is Screwdriver screwdriver)
                {
                    this.screwdriver = screwdriver;
                }
            }
        }
    #region Properties       
        public Screwdriver Screwdriver => screwdriver;
        public Hammer Hammer => hammer;
        public bool HasHammer => hammer != null;
        public bool HasScrewdriver => screwdriver != null;
    #end region
    }
    

    构造 x is Hammer 是一个布尔值,用于测试 x 是否属于 Hammer 类型。当用作if(x is Hammer y) { } 时,如果xHammer 类型,它将被y 变量在if 语句的范围内引用。

    【讨论】:

      【解决方案5】:

      根据您的工具箱类,它似乎最多可以包含 1 个锤子和最多 1 个螺丝刀。让我们暂时忽略您将变量定义为公共的;您可以使用以下类定义获得几乎相同的效果:

      public class Toolbox {
        public Hammer Hammer { get; set;}
        public Screwdriver Screwdriver { get; set;}
        public Toolbox() { }
      }
      

      那就不用写了(假设你已经定义了一个名为hammer的变量):

      Toolbox t = new Toolbox(hammer);
      

      你可以写:

      Toolbox t = new Toolbox() { Hammer = hammer };
      

      如果您需要添加其他工具,只需将新属性添加到 Toolbox 类即可。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-03
        • 2016-04-22
        • 1970-01-01
        • 2019-01-27
        • 1970-01-01
        • 2021-11-15
        • 2012-08-01
        相关资源
        最近更新 更多