どのように私はクラスのプロパティを再初期化またはリセットしますか?
-
22-08-2019 - |
質問
私は、デフォルト値を持つプロパティを持つクラスを作成しました。オブジェクトの有効期間のある時点で、私は、オブジェクトがインスタンス化されたとき、彼らが何であったかに戻って、オブジェクトのプロパティを「リセット」したいと思います。たとえば、のは、これはクラスだったとしましょう。
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()を使用するヘルパーメソッドを作成しますが、同じことをするでしょうPropertyInfoの値の代入にnullを設定するときに、なぜわざわざ可能性があります。
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;
}
}
あなたは、本質的に州のデザインパターン
あなたが望むすべての時間を返すために、特定のセーブポイントを作成することができます。また、これは、あなたが作成evereyインスタンスのバックアップにdiferent状態を持ってみましょう。あなたのクラスは常に変化している多くの性質を持っている場合、これはあなたの解決策になる可能性があります。
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));