C#自定义类集合的问题

时间:2011-03-01 17:12:35

标签: c#

在我的应用程序中,我有机器人,用户可以提供任意数量的不同任务。每个任务都是从抽象类Task:

派生的类
public abstract class Task
{
    string description = "default description";
    ...
}

public class Walk : Task
{
    string description = "Do walk";
    ...
}

public class Talk : Task
{
    string description = "Do talk";
    ...
}

因此每个机器人都有这些任务的集合。该集合的定义如下:

public class TaskCollection
{
    List<Task> _collection = new List<Task>();

    public void AddTask(string taskName)
    {
        _collection.Add( (Task)Activator.CreateInstance(null, taskName).Unwrap() );
    }

    public int Count()
    {
        return _collection.Count;
    }

    public Task GetElement( int i )
    {
        return _collection[i];
    }
}

为了测试它,我创建了一个TaskCollection并添加了一些这样的任务:

public TaskCollection tasks = new TaskCollection();
tasks.AddTask( "Walk" );
tasks.AddTask( "Talk" );

然后这段代码显示已添加的所有任务:

for( int i = 0; i < tasks.Count(); i++ )
{
    print( tasks.GetElement(i).description );
}

对于每个任务,它打印出“默认描述”而不是继承类中指定的描述。这是因为我将类实例作为任务进行投射吗?如果我删除该演员,我会收到此错误:

“System.Collections.Generic.List.Add(Task)”的最佳重载方法匹配有一些无效的参数。

希望清楚我在这里要做的事情。谁能看到我出错的地方?

5 个答案:

答案 0 :(得分:2)

以下是不对的:

public class Walk : Task
{
    string description = "Do walk";
    ...
}

您正在隐藏Task的描述成员,方法是在其子类中声明一个名为description的新成员。你必须得到警告说明这一点。

相反,请使用如下构造函数:

public class Walk : Task
{
    public Walk()
    {
        description = "Do walk";
    }
}

并在Task类中保护 description

protected string description = "...";

另外,如果您在循环中放入以下代码,您将获得正确的类型名称:

print( tasks.GetElement(i).GetType().FullName );

以下是一篇很好的文章,解释了那里发生的事情(会员隐藏):

Polymorphism, Method Hiding and Overriding in C#

答案 1 :(得分:2)

你在每个子类中声明了额外的变量,但是你总是从任务中打印 description变量。子类变量仅隐藏 Task中的变量。

这里有两个(或更多)选项。

首先,您可以使用多态:

public abstract class Task
{
    public virtual string Description { get { return "default description"; } }
}

public class Walk : Task
{
    public virtual string Description { get { return "Do walk"; } }
}

如果实际上不是“描述”,而是实际上想要一些行为,这将在每个具体实现中发生变化,这很有意义。

另一种选择是在Task中保留单个描述,但将其值传递给构造函数:

public abstract class Task
{
    private readonly string description;

    protected Task(string description)
    {
        this.description = description;
    }
}

public class Walk : Task
{
    public Walk() : base("Do walk")
    {
    }
}

现在你可以直接从子类设置字段,如果你可以访问它,但我强烈建议你保持私有。如果确实想要“推送”新值,请将其设为如下属性:

public class Task
{
    public string Description { get; protected set; }
}

这允许子类设置描述,但是从外部它只能被提取。

答案 2 :(得分:1)

您使用的是字段,而不是属性。在其他问题中,字段不能是多态的。多态性是您正在寻求的效果,其中成员定义在较高级别,其实现在较低级别提供(或覆盖)。

你想要的是属性。由于这是OO设计的练习,我会保留你所拥有的东西:

public abstract class Task
{
    public virtual string Description
    {
        get { return "default description"; }
    }
    ...
}

public class Walk : Task
{
    public overrides string Description
    { 
        get { return "Do walk"; }
    }
    ...
}

public class Talk : Task
{
    public overrides string Description
    { 
        get { return "Do talk"; }
    }
    ...
}

您使用这些字段完成的只是提供了一个相同名称的成员,该成员将较高级别成员隐藏在较低级别类的外向API中。如果您要将实例引用为WalkTalk(例如通过强制转换),那么您将看到相应的说明。但是当你将它作为一般Task引用时,定义得更多的成员是未知的。

请记住,我回答了您提出的问题,这就是为什么它无法正常工作以及如何使其发挥作用。这不是我为此特定任务选择的设计,因为您没有在派生类(对于此属性)中提供不同的功能,只是提供不同的数据。鉴于此,我将创建一个构造函数参数,该参数接受描述,然后在基类中返回它。

public abstract class Task
{
    public string Description { get; private set; }

    protected Task(string description)
    {
        this.Description = description;
    }
}

然后派生类看起来像:

public class Walk : Task
{
    public Walk() : base("Do walk") { }
}

(等)

答案 3 :(得分:0)

你不应该这样做

public abstract class Task
{
    string description = "default description";
    ...
}

public class Walk : Task
{
    string description = "Do walk";
    ...
}

看起来应该是这样的

public class Walk : Task
{
   public Walk
   {
      description = "Do walk";
   }
}

那应该在基类中设置字段,现在你实际上并没有这样做。

答案 4 :(得分:0)

使用以下方法:

public abstract class Task
{
    private const string description = "default description";
    public virtual string Description { get { return description; } }
}

public class Walk : Task
{
    private const string description = "Do walk";
    public override string Description { get { return description; } }
}