7

我想创建一个可以在属性中采用不同类型值的类。我正在尝试使用多态性来做到这一点,但我还没有学习如何正确地做到这一点,因此我请求建议。

我有一个基类和两个继承自它的类:

public abstract class BaseClass
{
    public string Name { get; set; }
    public Unit Unit { get; set; }
}

public class DerivedClassFloat : BaseClass
{
    public float Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}

public class DerivedClassString : BaseClass
{
    public string Value { get; set; }

    public override string ToString()
    {
        return Value;
    }
}

一切都很好,我可以创建一个列表并添加不同的专业子类。当我需要更改列表中项目的值时,我的问题就出现了:

foreach (var item in ListOfBaseClasses)
{
   if(item is DerivedClassFloat)
     ((DerivedClassFloat) item).Value = float.NaN;
   if (item is DerivedClassString)
      ((DerivedClassString) item).Value = string.Empty;
}

根据我所读到的,这看起来像是一种代码味道。有没有更好的方法可以根据我要分配的类型访问派生类的 value 属性?

当您想根据值创建正确的子类时怎么办?

BaseClass newClass = null;
if (phenotype is DerivedClassFloat)
    newClass = new DerivedClassFloat(){Value = 12.2};
if (phenotype is DerivedClassString)
    newClass = new DerivedClassString(){Value = "Hello"};                      

我读过关于覆盖虚拟方法的文章,但是如果我想处理该值,而不是添加或更改它……也许我遗漏了什么?


我应该让这个更具体,我很抱歉,我不习惯在这个伟大的网站上发布问题。

我需要一个由属性列表组成的属性。每个属性都有一个名称和一个值,但该值可以是不同的类型。例如:

public class Organism
{
    public string Name { get; set; }
    public List<Attribute> Attributes { get; set; }
}

public class Attribute
{
    public string AttributeName { get; set; }
    public object AttributeValue { get; set; }
}

对于给定的有机体,我可以有几个属性持有不同的值类型。我想避免使用对象类型,这样我就不必转换为正确的类型。我虽然属性多态是优雅地处理这种情况的解决方案,但后来我发现自己使用 If ..Then 这似乎与一开始的强制转换并没有太大区别。

4

6 回答 6

2

如果在您的特定情况下要重置Value,您可以在基类中定义一个抽象ResetValue方法,该方法将由派生类实现。

至于您的第二种情况,您应该查看Creational Design Patterns,特别是 Factory 和 Prototype 设计模式。

于 2012-04-21T19:37:04.150 回答
2

对于这种特殊情况,您可以使用泛型:

public abstract class BaseClass<T>
{
    public string Name { get; set; }
    public Unit Unit { get; set; }
    public T Value { get; set; }
}

public class DerivedClassFloat : BaseClass<float>
{
    public override string ToString()
    {
        return Value.ToString();
    }
}

public class DerivedClassString : BaseClass<string>
{
    public override string ToString()
    {
        return Value;
    }
}
于 2012-04-21T19:41:32.290 回答
1

您可以使用泛型来定义类型,实现子类会将类型设置Value为类型约束:

public abstract class BaseClass<T>
{
    public string Name { get; set; }
    public Unit Unit { get; set; }
    public T Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}

public class DerivedFloat : BaseClass<float> {}

public class DerivedString : BaseClass<string> {}
于 2012-04-21T19:41:18.320 回答
1

多态行为适用于抽象。根据您的尝试,您可以减少代码异味,以将代码中的尽可能多的可变性转移到基类中。

我建议不要使用如下的属性写入方法。你可以像下面这样。

public void setValue(string val, Type type);//move this to your base class

    Class MyValue{
private string strVal;
private int intVal;

//constructor
MyValue(string val, Type type){
     //check the type enum here and set the values accordingly
}
}

then when set values
foreach (var item in ListOfBaseClasses)
{
     item.setValue = MyValue("",Type.INT);
}
于 2012-04-21T19:48:03.907 回答
0

我不太确定你想用这种方法实现什么 - Value 属性不是同一类型,基类上也没有 Value 属性,这表明从基类派生的其他类型可能没有它一点也不。

如果您的所有类都需要 Value 属性,那么它可能应该是最通用的类​​型object- 您可以将它放在基类中,但这需要在派生类中转换值。但是你可以有一个NullObject表示没有值的值,你可以为每个派生类分配给 Value 属性。

于 2012-04-21T19:38:38.173 回答
0

您可以使用抽象工厂模式。考虑这个例子:

// Base class

class Button
{
    protected Button()
    {
    }

    public string Name { get; set; }
}

// Factory interface

public interface ButtonFactory
{
    Button CreateButton();
}

// And the concrete classes

class WindowsButton : Button
{
    // ...
}

class WindowsButtonFactory : ButtonFactory
{
    public Button CreateButton()
    {
        return new WindowsButton();
    }
}

class MacButton : Button
{
    // ...
}

class MacButtonFactory : ButtonFactory
{
    public Button CreateButton()
    {
        return new MacButton();
    }
}

此外,您可以将抽象工厂模式策略模式结合起来,封装随类型变化的自定义行为。

于 2012-04-21T19:58:45.547 回答