2013-04-18 7 views
15

अगर मैं एक सामान्य मद वर्ग है कि इस तरह दिखता है:सी # जेनरिक: सरल बनाएँ प्रकार हस्ताक्षर

abstract class Item<T> 
{ 
} 

और आइटम के एक कंटेनर है कि इस तरह दिखता है:

class Container<TItem, T> 
    where TItem : Item<T> 
{ 
} 

के बाद से TItem टी पर निर्भर करता है , क्या कंटेनर के प्रकार हस्ताक्षर को सरल बनाना संभव है ताकि इसमें केवल एक प्रकार का पैरामीटर लगे?

class Container<TItem> 
    where TItem : Item // this doesn't actually work, because Item takes a type parameter 
{ 
} 

तो मैं यह दृष्टांत कर सकते हैं इस प्रकार है::

class StringItem : Item<string> 
{ 
} 

var good = new Container<StringItem>(); 
var bad = new Container<StringItem, string>(); 

संकलक निकालना कि टी स्ट्रिंग है जब TItem StringItem है में सक्षम है, है ना होना चाहिए कुछ इस क्या मैं सच में चाहते है? मैं यह कैसे करूं?

वांछित उपयोग:

class MyItem : Item<string> 
{ 
} 

Container<MyItem> container = GetContainer(); 
MyItem item = container.GetItem(0); 
item.MyMethod(); 
+0

मुझे लगता है कि आप कर सकते हैं। इसका बहुरूपता। आप अमूर्त तरीकों को ओवरराइड कर सकते हैं। –

+0

उस स्थिति में आप स्ट्रिंगकॉन्टेनर क्लास को क्लास स्ट्रिंगकॉन्टेनर के रूप में बना सकते हैं जहां टीआईटीएम: आइटम RockWorld

+0

मुझे विश्वास नहीं है कि कंपाइलर _partially_ सामान्य प्रकार का अनुमान लगा सकता है। –

उत्तर

2

यह आपको क्या मुझे लगता है कि चाहते हैं क्या करना चाहिए। जाहिर है अब आप Container<string>Container<StringItem> नहीं कर रहे हैं, लेकिन जैसा कि आपने उपयोग उदाहरण शामिल नहीं किए हैं, मैं इसे एक समस्या नहीं देख सकता।

using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var myContainer = new Container<string>(); 

      myContainer.MyItems = new List<Item<string>>(); 
     } 
    } 

    public class Item<T> { } 

    public class Container<T> 
    { 
     // Just some property on your container to show you can use Item<T> 
     public List<Item<T>> MyItems { get; set; } 
    } 
} 

कैसे इस संशोधित संस्करण के बारे में:

using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var myContainer = new Container<StringItem>(); 

      myContainer.StronglyTypedItem = new StringItem(); 
     } 
    } 

    public class Item<T> { } 

    public class StringItem : Item<string> { } 

    // Probably a way to hide this, but can't figure it out now 
    // (needs to be public because it's a base type) 
    // Probably involves making a container (or 3rd class??) 
    // wrap a private container, not inherit it 
    public class PrivateContainer<TItem, T> where TItem : Item<T> { } 

    // Public interface 
    public class Container<T> : PrivateContainer<Item<T>, T> 
    { 
     // Just some property on your container to show you can use Item<T> 
     public T StronglyTypedItem { get; set; } 
    } 
} 
+0

यह संकलित करता है, लेकिन मुझे वास्तव में कंटेनर की आवश्यकता है, कंटेनर नहीं। – brianberns

+2

@brianberns: क्यों? (शिकायत नहीं, केवल संभावित उत्तरों के लिए उपयोगी होगा) –

+0

उपयोग जटिल हो जाता है, लेकिन कल्पना करें कि GetItem (int अनुक्रमणिका) नामक कंटेनर पर एक विधि है जिसे एक TItem वापस करना है, आइटम नहीं। यह कॉलर को टीआईटीम के लिए आइटम से इसे बिना किसी परिणाम के सीधे परिणाम पर TItem विधियों का आह्वान करने की अनुमति देता है। – brianberns

1

मुझे लगता है कि आपकी समस्या का एक संभव समाधान इंटरफेस IItem जोड़ रहा है और कोड संरचना निम्नलिखित की तरह हो जाएगा।

interface IItem { } 

abstract class Item<T> : IItem { } 

class Container<TItem> where TItem : IItem { } 

class StringItem: Item<string> { } 

और अब आप कर सकते हैं Container<StringItem>:

var container = new Container<StringItem>(); 
+0

अच्छा सुझाव नहीं है, लेकिन इसके साथ समस्या यह है कि कंटेनर को वास्तव में टीआईटीम के अंतर्निहित टी पैरामीटर के बारे में जानना आवश्यक है। – brianberns

+0

फिर यह संभव नहीं है। – hazzik

संबंधित मुद्दे