C # में एक सामान्य विधि बनाना


84

मैं समान विधियों के एक समूह को एक सामान्य विधि में संयोजित करने का प्रयास कर रहा हूं। मेरे पास कई विधियाँ हैं जो एक querystring, या null का मान लौटाती हैं यदि वह querystring मौजूद नहीं है या सही प्रारूप में नहीं है। यह काफी आसान होगा यदि सभी प्रकार मूल रूप से अशक्त थे, लेकिन मुझे पूर्णांक और दिनांक के लिए अशक्त सामान्य प्रकार का उपयोग करना होगा।

यहाँ अब मेरे पास क्या है। हालाँकि, यदि कोई संख्यात्मक मान अमान्य है, और यह दुर्भाग्य से मेरे परिदृश्य में एक मान्य मान है, तो यह 0 को वापस कर देगा। क्या कोई मेरी मदद कर सकता है? धन्यवाद!

public static T GetQueryString<T>(string key) where T : IConvertible
{
    T result = default(T);

    if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
    {
        string value = HttpContext.Current.Request.QueryString[key];

        try
        {
            result = (T)Convert.ChangeType(value, typeof(T));  
        }
        catch
        {
            //Could not convert.  Pass back default value...
            result = default(T);
        }
    }

    return result;
}

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

मुझे क्षमा करें, मुझे अभी भी समझ नहीं आया कि इस मामले में यह कैसे लागू होता है। मैं अभी भी काम करने के लिए फ़ंक्शन प्राप्त करने की कोशिश कर रहा हूं।
माइक कोल

उत्तरों को देखते हुए, मैं थोड़ा उलझन में हूं: क्या आपके कॉलर्स इंट या इंट का उपयोग कर पैरामीटर बना रहे हैं? टी के रूप में?

यह मुझे ऐसा लगता है, इस आंतरिक रूप से निपटने के बजाय, आपको अपवाद को फेंकने की विधि की अनुमति देनी चाहिए। हो सकता है कि सिर्फ मैं ही हूं, लेकिन किसी को भ्रम हो सकता है कि जब ChangeTypeअसफल होने के कारण उत्पन्न अपवाद को नहीं देख रहे हैं तो उनका कॉल हमेशा डिफ़ॉल्ट मान लौटा रहा है।
क्रश

जवाबों:


64

यदि आपने डिफ़ॉल्ट (T) का उपयोग करने के बजाय डिफ़ॉल्ट मान निर्दिष्ट किया है तो क्या होगा?

public static T GetQueryString<T>(string key, T defaultValue) {...}

यह कॉल करना भी आसान बनाता है:

var intValue = GetQueryString("intParm", Int32.MinValue);
var strValue = GetQueryString("strParm", "");
var dtmValue = GetQueryString("dtmPatm", DateTime.Now); // eg use today's date if not specified

नकारात्मक होने के कारण आपको अमान्य / अनुपस्थित क्वेरी मूल्यों को दर्शाने के लिए जादू के मूल्यों की आवश्यकता होती है।


हां, यह पूर्णांक के डिफ़ॉल्ट मान पर निर्भर होने से अधिक व्यवहार्य लगता है। मैं इसे ध्यान में रखूंगा। मैं अभी भी अपने मूल कार्य को सभी प्रकार के लिए काम करने की उम्मीद कर रहा हूं, हालांकि मैं बस गैर-सामान्य कार्यों का उपयोग कर सकता हूं।
माइक कोल

एक अमान्य पूर्णांक के लिए शून्य के अलावा कुछ और क्यों नहीं लौटाएं? आप ऐसा कुछ भी वापस कर सकते हैं जो आप चाहते हैं कि या तो वैध मूल्य नहीं है या पहले से ही एक विशेष उद्देश्य है, जैसे शून्य। तुम भी InvalidInteger या कुछ और अपने खुद के प्रकार बना सकते हैं। तुम एक बुरा querystring के लिए अशक्त लौट रहे हैं, है ना? आप इसे एक अमान्य पूर्णांक के लिए भी लौटा सकते हैं, इसलिए अशक्त का अर्थ होगा कि 'कुछ बुरा है और मेरे पास आपके लिए कोई मूल्य नहीं है', और हो सकता है कि फ़ंक्शन के संदर्भ में एक कारण बताएं?
डैन सेशरपस्टर

1
मान कैसे प्राप्त करें: long ? testजहां डिफ़ॉल्ट अशक्त होना चाहिए
अरशद

16

मुझे पता है, मुझे पता है, लेकिन ...

public static bool TryGetQueryString<T>(string key, out T queryString)

4
Try-Pattern अच्छी तरह से किसी भी नेट डेवलपर के लिए पता होना चाहिए। अगर आप मुझसे पूछें तो यह कोई बुरी बात नहीं है। F # या NET 4.0 में आप विकल्प (या च्वाइस)
क्रिश्चियन क्लॉसर

6
यदि कोई अन्य कारण नहीं है, तो मैं इससे बचने की कोशिश करता हूं क्योंकि मुझे आउटपुट वेरिएंट के "प्री-डिक्लेयर" होने से नफरत है, खासकर अगर यह कभी भी उपयोग नहीं किया जाता है - तो बेकार जो कोड की एक पूरी तरह से अच्छी लाइन हो सकती थी।
Jay

वास्तव में यह आपकी समस्या को हल करने का सबसे सरल तरीका है - एक फ़ंक्शन को ऊपर + दो सहायकों की तरह परिभाषित करें जो इस फ़ंक्शन का उपयोग करेंगे (वे 4 लाइनर होंगे)।
ग्रीनल्डमैन

1
मुझे जे पैटर्न के अनुसार ही पैटर्न के लिए कोशिश से नफरत है। यदि संभव हो तो मैं एक सामान्य कार्य को प्राथमिकता दूंगा, जो मेरा मूल लक्ष्य था।
माइक कोल

11
करो या मत करो, कोई परीक्षण नहीं है! <योदा>
खरगोश

12

इस बारे में क्या? से वापसी प्रकार परिवर्तित Tकरने के लिएNullable<T>

public static Nullable<T> GetQueryString<T>(string key) where T : struct, IConvertible
        {
            T result = default(T);

            if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
            {
                string value = HttpContext.Current.Request.QueryString[key];

                try
                {
                    result = (T)Convert.ChangeType(value, typeof(T));  
                }
                catch
                {
                    //Could not convert.  Pass back default value...
                    result = default(T);
                }
            }

            return result;
        }

त्रुटि: सामान्य प्रकार या विधि 'System.Nullable <T>' में पैरामीटर 'T' के रूप में उपयोग करने के लिए टाइप 'T' एक गैर-अशक्त मान होना चाहिए।
माइक कोल

आपको भी निर्दिष्ट करने की आवश्यकता है where T : struct
Aaronaught

@ माइक सी: आपको एक ही त्रुटि नहीं मिलनी चाहिए। संपादित कोड निश्चित रूप से संकलन करता है।
एरोनॉट

हाँ, अब मिल गया। तो क्या होता है जब मैं इसे स्ट्रिंग प्रकार के लिए कॉल करना चाहता हूं? इसे स्वीकार नहीं करेंगे जैसा कि अभी है।
माइक कोल

@ मायके, ऐसा नहीं लगता कि यह संभव है क्योंकि stringएक nullableमूल्य है
ग्रेविटोन

5

आप शायद मोनड के प्रकार का उपयोग कर सकते हैं (हालांकि मैं जे के उत्तर को पसंद करूंगा)

public class Maybe<T>
{
    private readonly T _value;

    public Maybe(T value)
    {
        _value = value;
        IsNothing = false;
    }

    public Maybe()
    {
        IsNothing = true;
    }

    public bool IsNothing { get; private set; }

    public T Value
    {
        get
        {
            if (IsNothing)
            {
                throw new InvalidOperationException("Value doesn't exist");
            }
            return _value;
        }
    }

    public override bool Equals(object other)
    {
        if (IsNothing)
        {
            return (other == null);
        }
        if (other == null)
        {
            return false;
        }
        return _value.Equals(other);
    }

    public override int GetHashCode()
    {
        if (IsNothing)
        {
            return 0;
        }
        return _value.GetHashCode();
    }

    public override string ToString()
    {
        if (IsNothing)
        {
            return "";
        }
        return _value.ToString();
    }

    public static implicit operator Maybe<T>(T value)
    {
        return new Maybe<T>(value);
    }

    public static explicit operator T(Maybe<T> value)
    {
        return value.Value;
    }
}

आपकी विधि इस तरह दिखाई देगी:

    public static Maybe<T> GetQueryString<T>(string key) where T : IConvertible
    {
        if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
        {
            string value = HttpContext.Current.Request.QueryString[key];

            try
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                //Could not convert.  Pass back default value...
                return new Maybe<T>();
            }
        }

        return new Maybe<T>();
    }

4

Convert.ChangeType().NET 2.0 BCL में nullable type या enumerations को सही ढंग से हैंडल नहीं करता है (मुझे लगता है कि यह BCL 4.0 के लिए निश्चित है)। बाहरी कार्यान्वयन को अधिक जटिल बनाने के बजाय, कनवर्टर को आपके लिए अधिक काम करने दें। यहां एक कार्यान्वयन है जिसका मैं उपयोग करता हूं:

public static class Converter
{
  public static T ConvertTo<T>(object value)
  {
    return ConvertTo(value, default(T));
  }

  public static T ConvertTo<T>(object value, T defaultValue)
  {
    if (value == DBNull.Value)
    {
      return defaultValue;
    }
    return (T) ChangeType(value, typeof(T));
  }

  public static object ChangeType(object value, Type conversionType)
  {
    if (conversionType == null)
    {
      throw new ArgumentNullException("conversionType");
    }

    // if it's not a nullable type, just pass through the parameters to Convert.ChangeType
    if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
    {
      // null input returns null output regardless of base type
      if (value == null)
      {
        return null;
      }

      // it's a nullable type, and not null, which means it can be converted to its underlying type,
      // so overwrite the passed-in conversion type with this underlying type
      conversionType = Nullable.GetUnderlyingType(conversionType);
    }
    else if (conversionType.IsEnum)
    {
      // strings require Parse method
      if (value is string)
      {
        return Enum.Parse(conversionType, (string) value);          
      }
      // primitive types can be instantiated using ToObject
      else if (value is int || value is uint || value is short || value is ushort || 
           value is byte || value is sbyte || value is long || value is ulong)
      {
        return Enum.ToObject(conversionType, value);
      }
      else
      {
        throw new ArgumentException(String.Format("Value cannot be converted to {0} - current type is " +
                              "not supported for enum conversions.", conversionType.FullName));
      }
    }

    return Convert.ChangeType(value, conversionType);
  }
}

तब गेटिइस्ट्रिंग <T> का आपका कार्यान्वयन हो सकता है:

public static T GetQueryString<T>(string key)
{
    T result = default(T);
    string value = HttpContext.Current.Request.QueryString[key];

    if (!String.IsNullOrEmpty(value))
    {
        try
        {
            result = Converter.ConvertTo<T>(value);  
        }
        catch
        {
            //Could not convert.  Pass back default value...
            result = default(T);
        }
    }

    return result;
}

0

मैं इस वर्ग की तरह एक वर्ग के साथ शुरू करना पसंद करता हूं {public int X {get; set;} public string Y {get; सेट; } // आवश्यकतानुसार दोहराएं

 public settings()
 {
    this.X = defaultForX;
    this.Y = defaultForY;
    // repeat ...
 }
 public void Parse(Uri uri)
 {
    // parse values from query string.
    // if you need to distinguish from default vs. specified, add an appropriate property

 }

इसने 100 परियोजनाओं पर अच्छा काम किया है। आप मानों को पार्स करने के लिए कई अन्य पार्सिंग समाधानों में से एक का उपयोग कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.