优雅的动态型铸造

时间:2011-08-19 07:37:48

标签: c#

我很感激您对以下方面的建议:

我正在使用多态性。我有一个基类和30个继承此基类的子类。我正在将这些子类的实例强制转换为基类类型,以便可以以更通用的方式处理它们。

我的问题是这个。 我需要访问特定于特定子类的公共属性。我是否需要编写一个巨大的case语句来检查类型并相应地向下转换以访问我需要的属性或者是否有更优雅的解决方案?

static void Main(string[] args)
    {

        animal slyvester = new cat();
        animal lassie = new dog();
        animal silver = new horse();

        //  Big ugly type checking code. If I have 30 types to check is there a better way?
        if (slyvester.GetType() == typeof(cat)) {
            Console.WriteLine(((cat)(animal)slyvester).PurrStrength);
        }
        else if(slyvester.GetType() == typeof(dog)) {

        }
        else if (slyvester.GetType() == typeof(horse))
        {

        }

        Console.ReadLine();
    }
}

public class animal { 

}

public class cat : animal {

    private string _purrStrength = "Teeth Shattering";

    public string PurrStrength {
        get { return _purrStrength; }
        set { _purrStrength = value; }
    }

}

public class dog : animal { 

}

public class horse : animal { 

}

5 个答案:

答案 0 :(得分:4)

您应该考虑基于接口的方法。使用接口,您可以定义一组操作(实现者必须遵守的合同),您的类型必须定义这些操作。例如,我们可以定义一个基本接口IAnimal

public interface IAnimal
{
  string GetSound();
}

我们可以从中定义一些动物类型:

public class Cat : IAnimal
{
  public string GetSound()
  {
    return "Meow!";
  }
}

public class Dog : IAnimal
{
  public string GetSound()
  {
    return "Woof!";
  }
}

现在,当我们要声明我们的动物时,我们声明它是IAnimal类型:

IAnimal cat = new Cat();
IAnimal dog = new Dog();

Console.WriteLine(cat.GetSound());
Console.WriteLine(dog.GetSound());

你可以更进一步,专攻你的动物:

public class Cat : IAnimal
{
  public virtual string GetSound()
  {
    return "Meow!";
  }
}

public class BigCat : Cat
{
  public override string GetSound()
  {
    return "Roar!";
  }
}

在后一个例子中,我可以对cat的GetSound方法进行默认实现,然后为我的大猫重写它。

基于接口的编程隐藏了对可怕类型转换的需求,因为接口保证了将提供的一组操作。

答案 1 :(得分:1)

如果你不必知道传递对象的确切类型,你只需要一个属性值,以防它在基类型中不存在,但实际类型中可能存在也可能不存在,可以使用反射:

        static void Main(string[] args)
        {
            animal slyvester = new cat();
            animal lassie = new dog();
            animal silver = new horse();

            DoSomething(slyvester);
            DoSomething(lassie);
            DoSomething(silver);

            Console.ReadLine();
        }

        static void DoSomething(animal entity)
        {
            string INeedThisProperty = "PurrStrength";
            Type type = entity.GetType();
            PropertyInfo property = type.GetProperty(INeedThisProperty);

            if (property != null && property.CanRead)
            {
                Console.WriteLine("Found: {0}", property.GetValue(entity, null));
            }
        }

答案 2 :(得分:0)

如果在获取属性的确切时刻你不知道它是什么类型,不知何故你必须找出它。

或者,我个人会做的,是尝试在基类上创建虚拟函数/属性,以更通用的方式描述我的子类操作,在具有实现的实现的子类中覆盖它们,并在使用上层调用函数/属性之后铸造物品。

答案 3 :(得分:0)

答案是使用polymorphism。我们的想法是在基接口中引入一个方法,或者在这种情况下引入基类。然后只需调用此方法!运行时将自动将调用委托给正确的类型。

请看下面修改后的实现:

public abstract class Animal
{
    public abstract void OutputInterestingFact();
}

public class Cat : Animal {

    private string _purrStrength = "Teeth Shattering";

    public string PurrStrength {
        get { return _purrStrength; }
        set { _purrStrength = value; }
    }

    public override void OutputInterestingFact()
    {
        Console.WriteLine(PurrStrength);
    }
}

public class Dog : Animal {
    public override void OutputInterestingFact()
    {
        // Do stuff for dog here
    }
}

public class Horse : Animal {
    public override void OutputInterestingFact()
    {
        // Do stuff for horse here
    }
}

我把Animal变成了一个抽象类。您还可以使用空方法体使OutputInterestingFact方法虚拟化。

我还将您的课程重命名为大写字母。这是习惯,因为这是C#中的练习,其他程序员会发现你的代码更容易阅读。

现在,使用它只需调用方法。

slyvester.OutputInterestingFact();

那够优雅吗?

答案 4 :(得分:0)

您的代码并未涵盖我能想到的所有情况,只有两种可能的解决方案:

class Animal {
    public abstract string PropertyValue { get; set; }
}

class Cat : Animal {
    public override string PropertyValue {
        get { return PurrStrength; }
        set { PurrStrength = value; }
    }
}

或者,对于多个属性:

class Animal {
    public virtual string[] GetPropertyValues() { return null; }
}

class Cat : Animal {
    public override string[] GetPropertyValues() {
        return new string[] { PurrStrength };
    }
}