如何创建和设置多态属性?

时间:2012-04-21 19:27:09

标签: c# design-patterns polymorphism

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

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

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

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

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 ..然后,这与首先没有什么不同。

6 个答案:

答案 0 :(得分:2)

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

至于你的第二个案例,你应该看看Creational Design Patterns,特别是工厂和原型设计模式。

答案 1 :(得分:2)

您可以将Generics用于此特定情况:

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

答案 2 :(得分: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> {}

答案 3 :(得分:1)

多态行为适用于抽象。根据您的尝试,您可以减少代码气味,将代码中的可变性移动到基础classess。

我建议使用如下的属性写入方法而不是。你可以这样做。

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

答案 4 :(得分:0)

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

如果你的所有类都需要一个Value属性,那么也许它应该是最通用的类​​型object - 你可以将它放在基类上,但这需要在派生类中转换值。 但是,您可以使用NullObject来表示缺少值,您可以为每个派生类赋予Value属性。

答案 5 :(得分:0)

您可以使用abstract factory pattern。考虑这个例子:

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

此外,您可以将abstract factory patternstrategy pattern结合使用,以封装随类型更改的自定义行为。