2011-08-19 152 views
0

我会感谢您对以下建议:优雅的动态类型铸造

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

我的问题是这样的。 我需要访问特定于特定子类的公共属性。我是否需要编写一个巨大的病例声明来检查类型并进行相应的转换以便访问我需要的属性或者是否有更优雅的解决方案?

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 { 

} 
+0

现在的问题是:你确定在查询哪一种类型的时刻? – Tigran

+0

每个动物都有特定的属性,你想阅读,或只是猫?换句话说,else if(slyvester.GetType()== typeof(dog))''会发生什么? –

+0

真正的问题是,你想要做什么? –

回答

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

谢谢大家的回复。这里有许多有效和有趣的回应。我不想在基类(或其他人提出的接口)中实现该属性,因为该属性没有被所有的子类实现,因此违反了基类(或接口)抽象是不行的?因此,我认为反射选项可能对我最有效。再次感谢! – dior001

+0

我的经验是,使用反射这种类型的问题迟早会让你回味无穷。 :-S – vidstige

+0

@vidstige我认为这是一个非常简单的例子。对于一个普遍的问题,这不是最好的选择,但是我发现它在一些边缘案例中非常有用。例如日志和适配器(鸭子打字)。但是你是对的,它会导致低性能和模棱两可的代码。但它有它的地方。 –

0

如果在财产获得精确的时刻,你dont't有任何线索是什么类型的,不知为何,你必须弄清楚它。

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

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

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

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

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

我所做的动物变成一个抽象类。您还可以使方法体虚拟为OutputInterestingFact

我也已将您的课程重新命名为以大写字母开头。使这成为一种习惯,因为这是C#中的练习,其他程序员会发现你的代码更易于阅读。

现在,使用这个只是调用方法。

slyvester.OutputInterestingFact(); 

这是否够优雅?

0

您的代码不包括所有我能想到的情况下,只是2个可能的解决方案:

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