2011-08-19 119 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 }; 
    } 
}