2016-01-04 8 views
5

मैं एक साधारण रिपोर्टिंग टूल बनाने की कोशिश कर रहा हूं, जहां कोई उपयोगकर्ता केपीआई, चार्ट, कुल फ़ंक्शन और अन्य पैरामीटर के सेट से चयन कर सकता है, एक बटन क्लिक करें, जिसके बाद एक डब्ल्यूसीएफ सेवा कहा जाता है, जो तब सभी डेटा के साथ एक कस्टम मॉडल देता है। यह तब एक एमवीसी/डब्ल्यूपीएफ आवेदन में प्रदर्शित किया जा सकता है (दोनों हो सकता है)।सेमी-विज्ञापन रिपोर्ट रिपोर्ट के लिए जेनेरिक इंटरफेस

चूंकि उपयोगकर्ता कई देशों से हो सकते हैं, इसलिए मैं सभी संख्याओं और शीर्षकों को चित्रित करने के लिए डेटा एनोटेशन का उपयोग करना चाहता हूं जो वर्तमान उपयोगकर्ता के लिए उपयोग की जाने वाली भाषा और संख्या प्रारूपों के अनुकूल है।

डेटा की लोडिंग और वह सब कुछ ठीक काम कर रहा है, कोई समस्या नहीं है। साथ ही, मैं डेटा एनोटेशन का उपयोग करता हूं, इसलिए सभी भाषा/संस्कृति-विशिष्ट सेटिंग्स की देखभाल की जाती है। समस्या तब शुरू होती है जब मैं उस मॉडल में सभी डेटा डालने का प्रयास करता हूं जिसे मैं उपयोगकर्ता को प्रदर्शित करना चाहता हूं।

जो मैं करने की कोशिश कर रहा हूं वह एक रिपोर्ट क्लास है, जिसमें कॉलम का संग्रह होता है। प्रत्येक कॉलम int/double/... मानों की एक सूची हो सकती है। अब, चूंकि मैं डब्ल्यूसीएफ से निपट रहा हूं और उपरोक्त स्पष्टीकरण का अर्थ है (जहां तक ​​मैं समझता हूं) जेनेरिकों का उपयोग, मुझे लगता है कि मैं कक्षाओं/डब्ल्यूसीएफ संचालन के लिए [ज्ञात टाइप] या [सर्विसकनाउन टाइप] का उपयोग कर सकता हूं, जबकि वास्तव में वापसी मूल्य के रूप में आधार प्रकार या इंटरफ़ेस। वास्तव में कभी भी यह कोशिश नहीं की, लेकिन मुझे कुछ अच्छी स्पष्टीकरण मिली जो मेरे लिए बहुत तार्किक लगती हैं, इसलिए मुझे लगता है कि इस भाग के लिए मेरे पास कोई बड़ा मुद्दा नहीं होगा (कम से कम मुझे उम्मीद है)।

अभी, मेरी इंटरफेस के रूप में कर रहे हैं इस तरह के (वास्तविक समस्या मेरे पास है पर ध्यान केंद्रित करने के लिए सरल):

public interface IReport<T> where T: IConvertible { ICollection<IColumn<T>> Columns { get; set; } } 
public interface IColumn<T> where T: IConvertible { ICollection<IValue<T>> Values { get; set; } } 
public interface IValue<T> where T: IConvertible { T Value { get; set; } } 

चूंकि प्रत्येक स्तंभ में मान हो सकता है किसी पूर्णांक/डबल/..., मुझे लगता है मैं (मुझे नहीं लगता कि मैं एक संग्रह के प्रकार पर एक डेटा एनोटेशन विशेषता का उपयोग कर सकते हैं) बस मूल्य के लिए एक वास्तविक वर्ग होना आवश्यक है, जैसे:

public class IntValue: IValue<int> 
{ 
    [DisplayFormat(DataFormatString = "{0:#,##0;-#,##0;'---'}", ApplyFormatInEditMode = true)] 
    public int Value { get; set; } 
} 
बेशक

, कि अजीब लग रहा है, जब से तुम सिर्फ कर सकता इसे एक सामान्य वर्ग मान बनाएं जो IValue लागू करता है और इसके साथ किया जाता है, लेकिन अगर मैं मूर्खतापूर्ण चीज करता हूं और प्रत्येक संभावित प्रकार के लिए एक वर्ग बनाएं (अब जब मैं इसे टाइप करता हूं, जो वास्तव में खराब लगता है, मुझे पता है), मैं DisplayFormat विशेषता का उपयोग कर सकता हूं और इस बारे में चिंता करने की ज़रूरत नहीं है कि यह उपयोगकर्ता को स्वयं पेश करेगा, यह ' हमेशा उपयुक्त होगा।

अब, कक्षाओं कि IColumn और iReport को लागू करने के लिए, कि सरल है:

public class Report<T>: IReport<T> where T: IConvertible 
{ 
    public ICollection<IColumn<T>> Columns { get; set; } 
    public Report() { Columns=new List<IColumn<T>>(); } 
} 

public class Column<T>: IColumn<T> where T: IConvertible 
{ 
    public ICollection<IValue<T>> Values { get; set; } 
    public Column() { Values = new List<IValue<T>>(); } 
} 

अंतरफलक और वर्गों की सूची से, आप तुरंत देखेंगे कि यह यह असंभव एक रिपोर्ट वाला राज्य बन गया है जहां कुछ कॉलम अन्य प्रकार हैं। इसलिए एक रिपोर्ट बनाना संभव नहीं है जहां कुछ कॉलम int हैं, कुछ डबल हैं, ... क्योंकि आईरपोर्ट में जेनेरिक बाधा आपको एक प्रकार निर्दिष्ट करती है, इसलिए आप सभी कॉलम के लिए इसके साथ अटक जाते हैं, क्योंकि यह मूल्य के अनुपात में फैलता है प्रत्येक कॉलम ... और यह वही है जो मैं वास्तव में चाहता हूं।

मुझे लगता है कि मुझे कहीं भी नहीं मिल रहा है, और शायद कुछ वास्तव में सरल याद आ रहा है, इसलिए सही दिशा में एक झुकाव की सराहना की जाएगी।

टीएल; डीआर: मैं गैर-सामान्य प्रकार में एक सामान्य संग्रह कैसे प्राप्त करूं?

+0

क्या आप अपनी रिपोर्ट को 'नया आईआरपोर्ट ' के रूप में नहीं बना सकते? – Baldrick

+0

जहां तक ​​मैं अब देख सकता हूं, यह मुझे एक इंट या डबल कॉलम जोड़ने की अनुमति नहीं देता है, क्योंकि यह अपेक्षा करता है कि उन्हें आईसीओन्वरिबल हो, और कोई भी आईकोनवर्टेबल कार्यान्वयन वर्ग नहीं। –

उत्तर

2

ठीक है, मैंने सुझाए गए समाधानों से प्रेरणा ली और नीचे एक भिन्नता लागू की। मैं समझता हूं कि जेनरिक का उपयोग बहुत ज्यादा नहीं करना चाहता, लेकिन यह अभी भी मुझे परेशान करता है। आखिरकार, मुझे कई प्रकार के कॉलम (या मान) चाहिए। इसके लिए जेनेरिक क्या हैं। इसके अलावा, मैं खेतों के स्वरूपण प्रदान करने के लिए एक अंतर्निहित तंत्र प्रदान करना चाहता था।

मैंने आईआरपोर्ट और आईसीओलंप इंटरफेस को सीधे सीधा छोड़ दिया, लेकिन मैं आईसीओएलएएम इंटरफेस में एक आईवाल्यू इंटरफेस का उल्लेख नहीं करता हूं। इसके बजाय, मैं एक अमूर्त वर्ग मान का उपयोग करता हूं जिसमें मैं स्वरूपण और डेटा पुनर्प्राप्ति (स्ट्रिंग प्रारूप में) के लिए कुछ आधार ढांचे को परिभाषित करता हूं।

वास्तविक IntValue/DoubleValue और वैल्यू बेसक्लास के बीच में, मैंने एक सामान्य वैल्यू क्लास जोड़ा जो जेनेरिक IValue इंटरफ़ेस लागू करता है जो डेटा फ़ील्ड प्रदान करने के अलावा कुछ और नहीं करता है इसलिए मुझे IntValue/DoubleValue कक्षाएं, और AsFormattedString विधि को कार्यान्वित करें, जो कि सामान्य बेसस्ट्रिंग विधि का उपयोग करता है जो मैं फॉर्म बेसक्लस कन्स्ट्रक्टर में बनाते हैं।

उस फॉर्मेटर का वास्तविक कार्यान्वयन IntValue/DoubleValue कक्षाओं में प्रदान किया जाता है, और एक मानक प्रारूप का उपयोग करने की संभावना देता है जिसे मैंने पहले ही हार्ड कोड किया है, या कक्षा उपयोगकर्ता द्वारा प्रदान किया गया एक कस्टम।

public interface IReport { ICollection<IColumn> Columns { get; set; } } 
public interface IColumn { ICollection<Value> Values { get; set; } } 

public interface IValue<T> where T: IConvertible { T Data { get; set; } } 

public abstract class Value 
{ 
    #region Formatting 

    protected IFormatProvider Formatter { get; set; } 
    protected abstract IFormatProvider GetFormatter(); 
    protected abstract string AsFormattedString(); 
    public override string ToString() { return AsFormattedString(); } 

    #endregion 

    public Value() { Formatter = GetFormatter(); } 
} 

public abstract class Value<T>: Value, IValue<T> where T: IConvertible 
{ 
    #region IValue members 

    public T Data { get; set; } 

    #endregion 

    #region Formatting 

    protected override string AsFormattedString() { return Data.ToString(Formatter); } 

    #endregion 
} 

public class IntValue: Value<int> 
{ 
    public IntValue() { } 
    public IntValue(string formatstring, int data) { Formatter = new IntFormatter(formatstring); Data = data; } 

    #region Formatting 

    protected override IFormatProvider GetFormatter() { return new IntFormatter(); } 

    internal class IntFormatter: CustomFormatter 
    { 
     public IntFormatter() : this("{0:#,##0;-#,##0;'---'}") { } 
     public IntFormatter(string formatstring) : base(formatstring) { } 
    } 

    #endregion 
} 

public class DoubleValue: Value<double> 
{ 
    public DoubleValue() { } 
    public DoubleValue(string formatstring, double data) { Formatter = new DoubleFormatter(formatstring); Data = data; } 

    #region Formatting 

    protected override IFormatProvider GetFormatter() { return new DoubleFormatter(); } 

    internal class DoubleFormatter: CustomFormatter 
    { 
     public DoubleFormatter() : this("{0:0.#0;-0.#0;'---'}") { } 
     public DoubleFormatter(string formatstring) : base(formatstring) { } 
    } 

    #endregion 
} 

public class ReportView: IReport 
{ 
    public ICollection<IColumn> Columns { get; set; } 
    public ReportView() { Columns = new List<IColumn>(); } 
} 

public class ReportColumn: IColumn 
{ 
    public ICollection<Value> Values { get; set; } 
    public ReportColumn() { Values = new List<Value>(); } 
} 

यह इस तरह के रूप किया जाता है:

// Creating a report 
    IReport report = new ReportView(); 

    // Adding columns 
    IColumn mycolumn = new ReportColumn(); 
    mycolumn.Values.Add(new IntValue() { Data = 1 }); 
    mycolumn.Values.Add(new DoubleValue() { Data = 2.7 }); 
    mycolumn.Values.Add(new IntValue("{0:#,##0;-#,##0;'---'}", 15)); 
    mycolumn.Values.Add(new DoubleValue("{0:0.#0;-0.#0;'---'}", 2.9)); 
    report.Columns.Add(mycolumn); 

    // Looping through each column, and get each value in the formatted form 
    foreach(var column in report.Columns) 
    { 
     foreach(var value in column.Values) { value.ToString(); } 
    } 

यदि इस बारे में सही किया कुछ जोड़े जाने के लिए/है, मैं सुनने के लिए खुशी होगी। मैं विज़िटर पैटर्न की जांच करूंगा जो बाइनरी वर्रियर द्वारा ऊपर की तरफ इशारा किया गया था, और पूरे सेटअप का परीक्षण करेगा। मुझे बताएं कि क्या मैं मूर्ख या खराब डिज़ाइन विकल्प बना देता हूं! मुझे शायद इसे प्रत्येक कॉल को प्रदान किए बिना पूरे कॉलम के लिए एक एकल प्रारूप प्रदान करने के लिए बाएं और दाएं को बदलने की आवश्यकता होगी, लेकिन मुझे लगता है कि बेस फ्रेमवर्क है।

1

मुझे लगता है कि प्रकार के लिए जेनेरिक का उपयोग करके आप पागल हो जाएंगे। मैंने जेनेरिक के उपयोग के साथ क्या गलत है इसका आकलन करने में काफी समय नहीं लगाया है। । । क्योंकि मुझे विश्वास नहीं है कि आपको जेनिक्स की ज़रूरत है।

रिपोर्ट सिर्फ कॉलम की एक सूची की जरूरत है, यह कॉलम

interface IReport 
{ 
    IEnumerable<IColumn> Columns {get;} 
} 

स्तंभ सिर्फ मानों की सूची की जरूरत के प्रकार के बारे में परवाह नहीं करता, और वास्तव में, एक बार मान खुद को देखभाल कर सकती , यह मूल्यों के प्रकारों की परवाह नहीं करता है।

interface IColumn 
{ 
    IEnumerable IValue Values {get;} 
} 

मूल्य सिर्फ (संभवतः सिर्फ एक स्ट्रिंग, या संभवतः "आकर्षित" करने के लिए एक दिया आयत आदि में अपने स्वयं के रूप में)

interface IValue 
{ 
    string AsString(); 
} 

तुम एक हो सकता है अपने स्वयं प्रस्तुत करने के लिए सक्षम होने की जरूरत विभिन्न प्रकारों के लिए टाइप किए गए मान कार्यान्वयन (IntValue, DoubleValue आदि), और एक बार जब वे IValue इंटरफ़ेस को लागू करते हैं तो आप हँस रहे हैं।

क्या यह समझ में आता है?

+0

यह करता है, यह करता है, धन्यवाद। मैं उस असली जल्दी कोशिश करूँगा। मैं डेटा एनोटेशन भाग मानता हूं, फिर केवल IValue के वास्तविक कार्यान्वयन में जाता है। हालांकि, अगर मैं कक्षाओं के उपयोगकर्ता को वास्तव में मूल्य प्रकार प्रदान करने के लिए मजबूर करना चाहता हूं तो क्या होगा? अभी यह तारों का एक सेट है, जो निश्चित रूप से काम करता है। लेकिन क्या होगा यदि मैं गणना में इस डेटा का उपयोग शुरू करना चाहता हूं, ...? –

+0

लाइन के नीचे मैं [विज़िटर पैटर्न] (https: // en।wikipedia.org/wiki/Visitor_pattern) डेटा पर विभिन्न समेकन और गणना लागू करने के लिए। एक बार मूल्य ज्ञात इंटरफ़ेस को कार्यान्वित करने के बाद आगंतुक इंटरफ़ेस पर कॉल के परिणामों के साथ क्या पसंद कर सकता है। जैसे आपके पास "डबलसम" विज़िटर है, जो IVALues के माध्यम से जाता है और उनके मानों को पूरा करने का प्रयास करता है। यदि यह किसी भी मूल्य को दोगुना करने के लिए मजबूर नहीं कर सकता है, तो वह उस सेल को शून्य के रूप में फेंक सकता है, या जो भी आपको पसंद है। –

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