كيف يمكنني إعادة تهيئة أو إعادة تعيين خصائص فئة؟

StackOverflow https://stackoverflow.com/questions/708352

سؤال

ولقد خلقت طبقة مع الخصائص التي تحتوي على قيم الافتراضية. في مرحلة ما من حياة الكائن، أود أن "إعادة تعيين" خصائص الكائن إلى ما كانت عليه عندما تم إنشاء مثيل الكائن. على سبيل المثال، دعنا نقول أن هذه الطبقة:

public class Truck {
   public string Name = "Super Truck";
   public int Tires = 4;

   public Truck() { }

   public void ResetTruck() {
      // Do something here to "reset" the object
   }
}

وبعد ذلك في مرحلة ما، بعد أن تم تغيير Name وTires الخصائص، يمكن استدعاء الأسلوب ResetTruck() وأن خصائص يتم إعادة تعيين إلى "سوبر شاحنة" و 4 على التوالي.

ما هي أفضل طريقة لإعادة الممتلكات إلى الافتراضات الثابت ترميز الأولية؟

هل كانت مفيدة؟

المحلول

ويمكنك الحصول على التهيئة في طريقة بدلا من رمز مصدر مع الإعلان. ثم يكون المنشئ وإعادة تعيين طريقة استدعاء الأسلوب التهيئة:

public class Truck {
   public string Name;
   public int Tires;

   public Truck() {
      Init();
   }

   public void ResetTruck() {
      Init();
   }

   private void Init() {
      Name = "Super Truck";
      Tires = 4;
   }
}

وهناك طريقة أخرى ليست لديها طريقة إعادة تعيين على الإطلاق. مجرد إنشاء مثيل جديد.

نصائح أخرى

وإذا لم إنشاء كائن غير مكلفة حقا (وإعادة تعيين ليس لسبب ما). لا أرى أي سبب لتطبيق أسلوب إعادة تعيين خاص. لماذا لا يتم فقط إنشاء مثيل جديد مع الحالة الافتراضية قابلة للاستخدام.

ما هو الغرض من إعادة استخدام المثال؟

إذا لم التهيئة الخاصة بك في طريقة إعادة يمكنك أن تكون على ما يرام:

public class Truck {
   public string Name;
   public int Tires;

   public Truck() {
    ResetTruck();
  }

   public void ResetTruck() {
      Name = "Super Truck";
      Tires = 4;
   }
}

والتأمل هو صديقك. هل يمكن إنشاء أسلوب مساعد لاستخدام Activator.CreateInstance () لتعيين القيمة الافتراضية من أنواع القيمة و'فارغ' لأنواع المرجعية، ولكن لماذا يزعج عندما وضع لاغية في SetValue لPropertyInfo سوف تفعل الشيء نفسه.

    Type type = this.GetType();
    PropertyInfo[] properties = type.GetProperties();
    for (int i = 0; i < properties.Length; ++i)
      properties[i].SetValue(this, null); //trick that actually defaults value types too.

لتمديد هذه لغرض الخاص بك، وأعضاء من القطاع الخاص:

//key - property name, value - what you want to assign
Dictionary<string, object> _propertyValues= new Dictionary<string, object>();
List<string> _ignorePropertiesToReset = new List<string>(){"foo", "bar"};

وتعيين القيم في منشئ الخاص بك:

 public Truck() {
    PropertyInfo[] properties = type.GetProperties();

    //exclude properties you don't want to reset, put the rest in the dictionary
    for (int i = 0; i < properties.Length; ++i){
        if (!_ignorePropertiesToReset.Contains(properties[i].Name))  
            _propertyValues.Add(properties[i].Name, properties[i].GetValue(this));
    }
}

وإعادة تعيين في وقت لاحق:

public void Reset() {
    PropertyInfo[] properties = type.GetProperties();
    for (int i = 0; i < properties.Length; ++i){
        //if dictionary has property name, use it to set the property
        properties[i].SetValue(this, _propertyValues.ContainsKey(properties[i].Name) ? _propertyValues[properties[i].Name] : null);     
    }
}

والتركيز على فصل الاهتمامات (مثل ذكر بريان في تعليق)، بديل آخر يتمثل في إضافة نوع TruckProperties (حتى أنت يمكن أن تضيف القيم الافتراضية لالمنشئ الخاص به):

public class TruckProperties
{
    public string Name
    {
        get; 
        set;
    }

    public int Tires
    {
        get; 
        set;
    }

    public TruckProperties()
    {
        this.Name = "Super Truck";
        this.Tires = 4;
    }

    public TruckProperties(string name, int tires)
    {
        this.Name = name;
        this.Tires = tires;
    }
}

وداخل الطبقة Truck الخاص بك، كل ما عليك أن تفعله هو إدارة مثيل من نوع TruckProperties، والسماح لها القيام إعادة تعيين لها.

public class Truck
{
    private TruckProperties properties = new TruckProperties();

    public Truck()
    {
    }

    public string Name
    {
        get
        {
            return this.properties.Name;
        }
        set
        {
            this.properties.Name = value;
        }
    }

    public int Tires
    {
        get
        {
            return this.properties.Tires;
        }
        set
        {
            this.properties.Tires = value;
        }        
    }

    public void ResetTruck()
    {
        this.properties = new TruckProperties();
    }
}

وهذا قد يكون بالتأكيد الكثير من (غير المرغوب فيه) النفقات العامة لمثل هذه فئة بسيطة، ولكن في مشروع أكبر / أكثر تعقيدا يمكن أن يكون مفيدا.

وهذا هو الشيء عن "أفضل" الممارسات ... في الكثير من الأحيان، وليس هناك حل سحري، ولكن توصيات فقط يجب أن تأخذ بعين الشك وحكمك على ما ينطبق عليك في حالة معينة.

وربما كنت بحاجة إلى حفظ القيم قبالة في مجالات خاصة، بحيث يمكن استعادتها في وقت لاحق. ربما شيء من هذا القبيل:

public class Truck
{
    private static const string defaultName = "Super Truck";
    private static const int defaultTires = 4;

    // Use properties for public members (not public fields)
    public string Name { get; set; }
    public int Tires { get; set; }

    public Truck()
    {
        Name = defaultName;
        Tires = defaultTires;
    }

    public void ResetTruck()
    {
        Name = defaultName;
        Tires = defaultTires;
    }

}

أنت تبحث أساسا ل الدولة تصميم نمط

إذا كنت تريد الماضية "الدولة" محددة من وجوه الخاص بك يمكنك إنشاء نقطة معينة إنقاذ للعودة في كل مرة تريد. هذا أيضا السماح لديك حالة diferent احتياطية لeverey المثال التي تقوم بإنشائها. إذا كنت فئة لديها العديد من الخصائص الذين هم في تغير مستمر، وهذا يمكن أن يكون الحل.

public class Truck
{
    private string _Name = "Super truck";
    private int _Tires = 4;

    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }
    public int Tires
    {
        get { return _Tires; }
        set { _Tires = value; }
    }

    private Truck SavePoint;

    public static Truck CreateWithSavePoint(string Name, int Tires)
    {
        Truck obj = new Truck();
        obj.Name = Name;
        obj.Tires = Tires;
        obj.Save();
        return obj;
    }

    public Truck() { }

    public void Save()
    {
        SavePoint = (Truck)this.MemberwiseClone();
    }

    public void ResetTruck()
    {
        Type type = this.GetType();
        PropertyInfo[] properties = type.GetProperties();
        for (int i = 0; i < properties.Count(); ++i)
            properties[i].SetValue(this, properties[i].GetValue(SavePoint));
    }
}

وأنا تحل مشكلة مماثلة مع التأمل. يمكنك استخدام source.GetType().GetProperties() للحصول على قائمة من كافة الخصائص التي تنتمي إلى الكائن.

وعلى الرغم من أن هذا ليس دائما حلا كاملا. إذا الكائن بتنفيذ عدة واجهات، ويمكنك أيضا الحصول على كل هذه الخصائص مع دعوة انعكاس الخاص بك.

وهكذا كتبت هذه الوظيفة البسيطة التي تتيح لنا المزيد من السيطرة على الخصائص التي نحن مهتمون في إعادة.

 public static void ClearProperties(object source, List<Type> InterfaceList = null, Type SearchType = null)
    {


        // Set Interfaces[] array size accordingly. (Will be size of our passed InterfaceList, or 1 if InterfaceList is not passed.)
        Type[] Interfaces = new Type[InterfaceList == null ? 1 : InterfaceList.Count];

        // If our InterfaceList was not set, get all public properties.
        if (InterfaceList == null)
            Interfaces[0] = source.GetType();
        else // Otherwise, get only the public properties from our passed InterfaceList
            for (int i = 0; i < InterfaceList.Count; i++)
                Interfaces[i] = source.GetType().GetInterface(InterfaceList[i].Name);


        IEnumerable<PropertyInfo> propertyList = Enumerable.Empty<PropertyInfo>();
        foreach (Type face in Interfaces)
        {
            if (face != null)
            {
                // If our SearchType is null, just get all properties that are not already empty
                if (SearchType == null)
                    propertyList = face.GetProperties().Where(prop => prop != null);
                else // Otherwise, get all properties that match our SearchType
                    propertyList = face.GetProperties().Where(prop => prop.PropertyType == SearchType);

                // Reset each property
                foreach (var property in propertyList)
                {
                    if (property.CanRead && property.CanWrite)
                        property.SetValue(source, null, new object[] { });
                }
            }
            else
            {
                // Throw an error or a warning, depends how strict you want to be I guess.
                Debug.Log("Warning: Passed interface does not belong to object.");
                //throw new Exception("Warning: Passed interface does not belong to object.");
            }
        }
    }

وانها الاستخدام:

// Clears all properties in object
ClearProperties(Obj);
// Clears all properties in object from MyInterface1 & MyInterface2 
ClearProperties(Obj, new List<Type>(){ typeof(MyInterface1), typeof(MyInterface2)});
// Clears all integer properties in object from MyInterface1 & MyInterface2
ClearProperties(Obj, new List<Type>(){ typeof(MyInterface1), typeof(MyInterface2)}, typeof(int));
// Clears all integer properties in object
ClearProperties(Obj,null,typeof(int));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top