문제

기본값이있는 속성이있는 클래스를 만들었습니다. 물체의 수명의 어느 시점에서, 나는 객체의 특성을 객체가 인스턴스화되었을 때의 것들로 다시 "재설정"하고 싶습니다. 예를 들어, 이것이 수업이라고 가정 해 봅시다.

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 ()를 사용하여 값이 값 유형의 기본값을 설정하고 참조 유형의 경우 'null'을 설정하는 도우미 방법을 만들 수 있지만 PropertyInfo의 setValue에서 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);     
    }
}

우려의 분리에 대한 초점 (의견에 언급 된 Brian과 같은)은 또 다른 대안은 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 인스턴스에 대한 백업에 대한 다른 상태를 가질 수있게합니다. 클래스에 끊임없이 변화하는 속성이 많으면 솔루션이 될 수 있습니다.

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