2011-03-24 29 views
5

मैंने immutable class डिज़ाइन किया है, क्योंकि मैं इसके लिए मूल्य-अर्थशास्त्र चाहता हूं। मैं कक्षाअपरिवर्तनीयता सुनिश्चित करने के लिए इकाई परीक्षण बनाना

// "This class is immutable, don't change this when adding new features to it."

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

(सी # 2.0 और एनयूनीट का उपयोग करना, अगर यह किसी के लिए महत्वपूर्ण है)।

+0

अनाम डाउनवॉटर को: जब आप मानते हैं कि इस प्रश्न में कुछ गड़बड़ है, तो कृपया मुझे सूचित करें। –

उत्तर

8

अपरिवर्तनीयता के परीक्षण के लिए आप FieldInfo.IsInitOnly का उपयोग कैसे कर सकते हैं इस पर मेरी टिप्पणी का बैक अप लेने के लिए एक उदाहरण।

इस बात पर विचार करने के लिए और अधिक विशेष मामले हो सकते हैं कि मैंने string को कैसे संभाला है, लेकिन यह केवल मुझे लगता है कि झूठे नकारात्मक संकेत देंगे, यानी आपको कुछ बताएगा कि यह कुछ नहीं है, न कि दूसरी तरफ।

तर्क यह है कि प्रत्येक फ़ील्ड readonly होना चाहिए और एक अपरिवर्तनीय प्रकार होना चाहिए। ध्यान दें कि यह स्वयं संदर्भित प्रकार या परिपत्र संदर्भों का सामना नहीं करेगा।

using System; 
using System.Linq; 
using System.Reflection; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace ImmutableTests 
{ 
    [TestClass] 
    public class AssertImmutableTests 
    { 
     [TestMethod] 
     public void Is_int_immutable() 
     { 
      Assert.IsTrue(Immutable<int>()); 
     } 

     [TestMethod] 
     public void Is_string_immutable() 
     { 
      Assert.IsTrue(Immutable<string>()); 
     } 

     [TestMethod] 
     public void Is_custom_immutable() 
     { 
      Assert.IsTrue(Immutable<MyImmutableClass>()); 
     } 

     [TestMethod] 
     public void Is_custom_mutable() 
     { 
      Assert.IsFalse(Immutable<MyMutableClass>()); 
     } 

     [TestMethod] 
     public void Is_custom_deep_mutable() 
     { 
      Assert.IsFalse(Immutable<MyDeepMutableClass>()); 
     } 

     [TestMethod] 
     public void Is_custom_deep_immutable() 
     { 
      Assert.IsTrue(Immutable<MyDeepImmutableClass>()); 
     } 

     [TestMethod] 
     public void Is_propertied_class_mutable() 
     { 
      Assert.IsFalse(Immutable<MyMutableClassWithProperty>()); 
     } 

     private static bool Immutable<T>() 
     { 
      return Immutable(typeof(T)); 
     } 

     private static bool Immutable(Type type) 
     { 
      if (type.IsPrimitive) return true; 
      if (type == typeof(string)) return true; 
      var fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 
      var isShallowImmutable = fieldInfos.All(f => f.IsInitOnly); 
      if (!isShallowImmutable) return false; 
      var isDeepImmutable = fieldInfos.All(f => Immutable(f.FieldType)); 
      return isDeepImmutable; 
     } 
    } 

    public class MyMutableClass 
    { 
     private string _field; 
    } 

    public class MyImmutableClass 
    { 
     private readonly string _field; 
    } 

    public class MyDeepMutableClass 
    { 
     private readonly MyMutableClass _field; 
    } 

    public class MyDeepImmutableClass 
    { 
     private readonly MyImmutableClass _field; 
    } 

    public class MyMutableClassWithProperty 
    { 
     public string Prop { get; set; } 
    } 
} 
+0

अच्छा दृष्टिकोण। धन्यवाद। – denver

+0

शायद मैं कुछ गलत तरीके से देख रहे हैं, लेकिन एक सार्वजनिक int युक्त कक्षा, इस उदाहरण को अपरिवर्तनीय माना जाएगा, है ना? जबकि वास्तव में यह व्यवहार्य है। –

+0

@ टोंनीटीलेंस आपके मतलब पर निर्भर करता है, 'सार्वजनिक int ए {प्राप्त करें; निजी सेट;} 'उत्परिवर्तनीय,' सार्वजनिक int ए {get;} 'mutable नहीं। 'सार्वजनिक int ए;' mutable। – weston

3

इस पोस्ट में कुछ विचार हैं। हालांकि, ऐसा लगता है कि कोई निश्चित तरीका नहीं है।

How do I find out if a class is immutable in C#

+0

+1, यह उत्तर भी उपयोगी है, लेकिन एसओ के नियमों के लिए मैं केवल एक स्वीकार कर सकता हूं। –

+1

"केवल एक ही हो सकता है!"और SO: p – MattC

7

आप की जांच कर सकता है कि वर्ग बंद है, और प्रतिबिंब की जांच की जाती है कि प्रत्येक क्षेत्र केवल पढ़ने के लिए (FieldInfo.IsInitOnly का प्रयोग करके) का उपयोग करते हुए।

बेशक, कि केवल यह सुनिश्चित करता है उथले अचल स्थिति - यह वहाँ में एक List<int> क्षेत्र डाल, और फिर सूची की सामग्री को परिवर्तित करने से कोई रोक नहीं होगा।

+0

+1 पर 'outskeeted' असामान्य नहीं है और स्वीकार किया गया है (मैं 95% समाधान के साथ रह सकता हूं) –

+0

अच्छा विचार यह है कि मैंने इसे 'AssertImutable ()' विधि बनाने के लिए उपयोग किया है जो आप कर सकते हैं गहरी अपरिवर्तनीयता का दावा करने के लिए क्षेत्र के प्रकारों पर रिक्त रूप से कॉल करें। – weston

+0

@weston क्या आपने इसे साझा किया है? – denver

2

यह सुनिश्चित नहीं है कि आपने NDepend के बारे में सुना है, लेकिन यह टूल आपको अपने स्रोत कोड पर "आत्मनिरीक्षण" करने और असेंबली संकलित करने की अनुमति देता है और निर्भरता जांच सहित बहुत सारे जादू करता है और बहुत कुछ करता है।

ऐसी एक जांच अपरिवर्तनीयता के लिए एक जांच है। उदाहरण के लिए, मैं एक IImmutable मार्कर इंटरफेस है, और NDepend अपने निर्माण में विफल रहता है, यदि कोई हो प्रकार इस इंटरफेस है, लेकिन परिवर्तनशील हैं, निम्न क्वेरी का उपयोग:

WARN IF Count > 0 IN SELECT TYPES WHERE 
    Implement "MyCompany.MyAssemblies.Dto.IImmutable" AND 
    !IsImmutable 

आप भी इसे कॉन्फ़िगर कर सकते हैं उल्लंघन रिपोर्ट उत्पन्न करने के साथ-साथ विफलता निर्माण करता है।

स्पष्ट रूप से यह वास्तव में एक इकाई परीक्षण नहीं है। हालांकि, इसे आपके निर्माण के हिस्से के रूप में एकीकृत किया जा सकता है, और यूनिट टेस्ट के रूप में आपके निर्माण में असफल हो सकता है, इसलिए मैंने सोचा कि मैं इसका उल्लेख करूंगा!

here देखें और वास्तव में क्या करता है इसके बारे में अधिक जानकारी के लिए।

+0

+1, यह उत्तर भी उपयोगी है, लेकिन मैं केवल एक को स्वीकार कर सकता हूं। शायद मैं यह देखने के लिए एनडेंडेंड का प्रयास करूंगा कि हमारी परियोजनाओं की कीमत चार मूल्य है या नहीं। –

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