2012-01-09 13 views
6

मैं वस्तुओं के लिए जहां कुंजी प्रकार Type की है की एक सामान्य शब्दकोश है:टाइप-सुरक्षित एक शब्दकोश के साथ वस्तुओं की सेटिंग है कि एक `Type` कुंजी

public class DynamicObject : IDictionary<Type, object> 

विचार है कि इस वस्तु में साझा किया जाता है एक प्लगइन-आधारित आर्किटेक्चर और प्लगइन के बीच संघर्ष को रोकने के लिए एक प्रकार (जो प्लगइन .dll में रह सकता है) को कुंजी के रूप में उपयोग किया जाता है। इस प्रकार का उपयोग मेटाडेटा को फ़ील्ड के बारे में भी संग्रहीत करने के लिए किया जाता है (जैसे कि उस फ़ील्ड का विवरण या उस फ़ील्ड का वास्तविक प्रकार)। भले ही प्रकार UsernameField बारे में पता है -

DynamicObject someObject; 
string someValue; 
someObject[typeof(UsernameField)] = someValue; 

इस के साथ ही समस्या यह है कि इस टाइप सुरक्षित नहीं है:

वर्तमान में प्लगइन्स इस के समान कोड का उपयोग कर इस वस्तु पर क्षेत्रों का मूल्य निर्धारित करने की आवश्यकता जिस मूल्य की अपेक्षा की जा रही है उसका सटीक प्रकार (उदाहरण के लिए int या इस मामले में string), यहां दिया गया मान केवल एक ऑब्जेक्ट के रूप में टाइप किया गया है। मैं प्रॉपर्टी प्रकार को सुरक्षित/स्थापित करने के लिए जेनेरिक का उपयोग करना चाहता हूं लेकिन मुझे यकीन नहीं है कि कैसे। अब तक सबसे अच्छा मैं ले कर आए हैं यह है:

// Field is a base class for all types used as keys on DynamicObject 
[Description("Username of the user")] 
public class UsernameField : Field 
{ 
    public static void Set(DynamicObject obj, string value) 
    { 
     obj[typeof(UsernameField)] = someValue; 
    } 
} 

// To set fields 
UsernameField.Set(obj, someValue); 

इस प्रकार सुरक्षित है, लेकिन इसका मतलब यह मेरा क्षेत्र प्रकारों में से प्रत्येक (जैसे UsernameField) एक लगभग समान स्थिर Set विधि है।

मेरे रास्ते के प्रत्येक प्रकार के लगभग समान तरीकों के बिना इस तरह के मूल्यों में टाइप-सुरक्षित पहुंच कैसे हो सकती है?

एक तरफ के रूप में, Type का उपयोग इस तरह की एक कुंजी के रूप में कर रहा है या ऐसे छिपे हुए नुकसान हैं जिनके बारे में मुझे अभी तक पता नहीं है?

public interface IPlugin { 
    string Name { get; } 
    string Author { get; } 
    string Description { get; } 
    void Init(); 
} 

और फिर एक Dictionary<Type, IPlugIn> का उपयोग करें:

+0

क्या 'Type' और' यहां object' के बीच संबंध है? 'टाइप'' प्रकार का 'ऑब्जेक्ट' हमेशा होता है? –

+0

क्या आप MyObject और MyField को और अधिक सार्थक नाम दे सकते हैं ताकि हम उनके अर्थ को समझ सकें? –

+0

@MarcGravell इस समय मान वास्तव में कुंजी के समान प्रकार के नहीं होते हैं, इसलिए ऊपर 'कुछ वैल्यू' वास्तव में 'स्ट्रिंग' नहीं है 'माईफिल्ड'। यह कहकर कि मैं इसे बदल सकता हूं ताकि यह मामला हो (आपका अब हटाए गए उत्तर को देखकर) – Justin

उत्तर

2

एक अंतरफलक है कि आपके सभी प्लग-इन को लागू करना चाहिए परिभाषित करें।

आमतौर पर इंटरफ़ेस को एक अलग डीएल में घोषित किया जाता है (जैसे "MyCompany.MyProject.PlugIns.Contracts.dll")।


संपादित करें: ठीक है, मुझे लगता है कि मुझे पता है कि तुम अब क्या मतलब है।

यह चाल एक सामान्य Set विधि के साथ Field और UsernameField के बीच एक सामान्य वर्ग है। तथ्य यह है कि Field सामान्य नहीं है, यह सभी फ़ील्ड प्रकारों को असाइन करने योग्य बनाता है। यह मामला नहीं होगा, अगर इसे Field<T> के रूप में घोषित किया गया था।

public abstract class Field 
{ 
} 

public abstract class GenericField<T> : Field 
{ 
    public void Set(DynamicObject obj, T value) 
    { 
     obj[this.GetType()] = value; 
    } 
} 

public class UsernameField : GenericField<string> 
{ 
    #region Singleton Pattern 

    public static readonly UsernameField Instance = new UsernameField(); 

    private UsernameField() { } 

    #endregion 

} 

क्योंकि हम Set विधि में GetType कॉल करने की आवश्यकता है, हम इसे static के रूप में घोषित नहीं कर सकते। इसलिए, मैंने सिंगलटन पैटर्न का उपयोग किया।

अब, हम एक प्रकार सुरक्षित तरीके से क्षेत्र निर्धारित कर सकते हैं:

UsernameField.Instance.Set(obj, "Joe"); 

अलावा 1:

अब चूंकि क्षेत्रों एकमात्र हैं, तो आप क्षेत्रों में से कुंजी के रूप में इस्तेमाल कर सकते हैं अपने प्रकार के बजाय शब्दकोश।

public class DynamicObject : IDictionary<Field, object> { } 

और Set बन जाएगा:

public void Set(DynamicObject obj, T value) 
{ 
    obj[this] = value; 
} 

अलावा 2:

आप भी इस तरह DynamicObject निर्धारित कर सकते हैं:

public class DynamicObject : Dictionary<Field, object> 
{ 
    public void Set<T>(GenericField<T> field, T value) 
    { 
     this[field] = value; 
    } 
} 

अब आप मूल्यों lik सेट कर सकते हैं ई यह:

obj.Set(UsernameField.Instance, "Sue"); 

यह प्रकार सुरक्षित है और अधिक प्राकृतिक लगता है। Set विधि GenericField में अब अप्रचलित है।

+0

यह एक संभावना है (हालांकि फ़ील्ड प्लगइन के बीच साझा किया जा सकता है और इसलिए मैं 'इंटरफेस आईफिल्ड' और 'डिक्शनरी <टाइप, आईफिल्ड>' का उपयोग करता हूं), हालांकि ऐसा लगता है कि "साफ" ... – Justin

+0

इस स्थिति में 'गेट टाइप' का उपयोग करने के विकल्प आप 'MethodInfo.GetCurrentMethod()। प्रतिबिंबित टाइप टाइप कर सकते हैं यदि प्राथमिकता' सेट 'स्थिर बनाना है। –

+0

यह 'डायनेमिकफिल्ड्स। जेनरिक फ़ील्ड \' 1 [टी] 'वापस करेगा, लेकिन व्युत्पन्न कक्षा नहीं। –

1

मुझे सिर्फ प्रश्न का बिंदु याद आ रहा है, लेकिन यदि लक्ष्य प्रकार सुरक्षा प्राप्त करने के लिए आवश्यक कोड डुप्लिकेशंस की मात्रा को कम करना है, तो फ़ील्ड के बजाय फ़ील्ड के प्रकार के आधार पर एक्सेसर हेल्पर्स को परिभाषित क्यों न करें:

public abstract class StringField<T> : Field 
{ 
    public static void Set(DynamicObject obj, string value) 
    { 
     obj[typeof(T)] = someValue; 
    } 
} 

public class UsernameField : StringField<UsernameField> { } 

// To set fields 
UsernameField.Set(obj, someValue); 

संपादित करें:

या आप सिंगलटन बिना Oliver's solution की एक मामूली बदलाव इस्तेमाल कर सकते हैं:

public abstract class GenericField<T, U> : Field 
{ 
    public static void Set(DynamicObject obj, T value) 
    { 
     obj[typeof(U)] = value; 
    } 
} 

public class UsernameField : GenericField<string, UsernameField> { } 
1

मूल्य प्राप्त करने और सेट करने के लिएको DynamicObject के बारे में पता नहीं होना चाहिए। आप DyanmicObject मूल्यों को प्राप्त करने और सेट करने के लिए संभाल सकते हैं, लेकिन मुझे लगता है कि DynamicObject का Field उदाहरणों के संग्रह के रूप में एक बेहतर तरीका है, और प्रत्येक फ़ील्ड का अपना मूल्य होता है। कुछ इस तरह:

interface IField 
{ 
    object Value { get; set; } 
} 

interface IField<T> : IField 
{ 
    new T Value { get; set; } 
} 

abstract class BaseField<T> : IField<T> 
{ 
    T _value; 
    public T Value 
    { 
     get { return _value; } 
     set 
     { 
      // could add stuff like OnValueChanging, IsValueValid, etc... 
      this._value = value; 
     } 
    } 

    object IField.Value 
    { 
     get { return Value; } 
     set { Value = (T)value; } 
    } 
} 

class DynamicObject : List<IField> 
{ 
    public TField GetField<TField>() where TField : IField 
    { 
     return this.OfType<TField>().Single(); 
    } 
} 

और उपयोग तो होगा:

class UsernameField : BaseField<string> { } 

[TestMethod] 
public void test() 
{ 
    var parent = new DynamicObject(); 
    var field = new UsernameField() { Value = "the username" }; 
    parent.Add(field); 
    Assert.AreEqual("the username", parent.GetField<UsernameField>().Value); 
} 

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

  • कोई संबंधित समस्या नहीं^_^