Domanda

Ho creato una classe con le proprietà che hanno valori predefiniti. Ad un certo punto nel corso della vita di un oggetto, mi piacerebbe "reset" proprietà dell'oggetto di nuovo a quello che erano quando l'oggetto è stato istanziato. Per esempio, diciamo che questa è stata la classe:

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

   public Truck() { }

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

Poi ad un certo punto, dopo che le proprietà Name e Tires sono stati cambiati, il metodo ResetTruck() potrebbe essere chiamato e le proprietà verrebbe ripristinato torna a "Super Truck" e 4, rispettivamente.

Qual è il modo migliore per ripristinare le proprietà ai valori predefiniti hardcoded iniziali?

È stato utile?

Soluzione

Si può avere l'inizializzazione in un metodo, invece di inlining con la dichiarazione. Poi hanno il costruttore e ripristinare il metodo chiamare il metodo di inizializzazione:

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

   public Truck() {
      Init();
   }

   public void ResetTruck() {
      Init();
   }

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

Un altro modo non è quello di avere un metodo di ripristino a tutti. Basta creare una nuova istanza.

Altri suggerimenti

A meno che la creazione dell'oggetto non è molto costoso (e Reset non è per qualche motivo). Non vedo alcuna ragione per implementare un metodo di reset speciale. Perché non solo crea una nuova istanza con uno stato predefinito utilizzabile.

Qual è lo scopo di riutilizzare l'istanza?

Se avete fatto il vostro inizializzazione in un metodo di ripristino si può essere pronti per partire:

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

   public Truck() {
    ResetTruck();
  }

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

La riflessione è tuo amico. È possibile creare un metodo di supporto da utilizzare Activator.CreateInstance () per impostare il valore predefinito di tipi di valore e 'nullo' per i tipi di riferimento, ma perché preoccuparsi quando si imposta nulla su ImpostaValore di un PropertyInfo farà lo stesso.

    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.

Per estendere questo per il vostro scopo, hanno soci privati:

//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"};

Impostare i valori nel costruttore:

 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));
    }
}

Ripristina in seguito:

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);     
    }
}

messa a fuoco della separazione degli interessi (come Brian accennato nei commenti), un'altra alternativa potrebbe essere quella di aggiungere un tipo TruckProperties (si potrebbe anche aggiungere i valori di default per il suo costruttore):

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;
    }
}

All'interno della vostra classe Truck, tutto quello che vi fare è gestire un'istanza del tipo TruckProperties, e lasciar fare il suo ripristino.

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();
    }
}

Questo certamente può essere un sacco di overhead (indesiderati) per una classe così semplice, ma in un progetto più ampio / più complesso potrebbe essere vantaggioso.

Questa è la cosa di "migliori" pratiche ... un sacco di volte, non c'è pallottola d'argento, ma solo raccomandazioni è necessario portare con scetticismo e il vostro giudizio migliore su ciò che si applica a voi in un caso particolare.

Si sarebbe probabilmente necessario per salvare i valori fuori nei campi privati, in modo che possano essere ripristinati in seguito. Forse qualcosa di simile a questo:

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;
    }

}

Si sta essenzialmente cercando la Stato design pattern

Se si desidera una specifica passato "stato" del vostro oggetto è possibile creare un particolare punto di salvataggio per tornare ogni volta che si desidera. Questo permetterà anche di avere uno stato diferent di backup per everey esempio, che si crea. Se classe ha molte proprietà che sono in costante cambiamento, questa potrebbe essere la vostra soluzione.

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));
    }
}

ho risolto un problema simile con la riflessione. È possibile utilizzare source.GetType().GetProperties() per ottenere un elenco di tutte le proprietà che appartengono all'oggetto.

Anche se, questo non è sempre una soluzione completa. Se il vostro oggetto implementa diverse interfacce, si riceverà anche tutte quelle proprietà con la chiamata di riflessione.

Così ho scritto questa semplice funzione che ci dà più controllo di cui proprietà ci interessa il ripristino.

 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.");
            }
        }
    }

Ed è l'uso:

// 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));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top