我创建了一个具有默认值属性的类。在对象生命周期的某个时刻,我想将对象的属性“重置”回实例化对象时的属性。例如,假设这是类:
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()
方法,并将属性重置为“Super Truck”和4分别。
将属性重置为初始硬编码默认值的最佳方法是什么?
答案 0 :(得分:11)
您可以在方法中进行初始化,而不是使用声明进行内联。然后让构造函数和reset方法调用初始化方法:
public class Truck {
public string Name;
public int Tires;
public Truck() {
Init();
}
public void ResetTruck() {
Init();
}
private void Init() {
Name = "Super Truck";
Tires = 4;
}
}
另一种方法是根本没有重置方法。只需创建一个新实例。
答案 1 :(得分:4)
除非创建对象非常昂贵(并且Reset不是出于某种原因)。我认为没有理由实施特殊的重置方法。为什么不创建具有可用默认状态的新实例。
重用实例的目的是什么?
答案 2 :(得分:3)
如果你在重置方法中进行了初始化,那么你可以去:
public class Truck {
public string Name;
public int Tires;
public Truck() {
ResetTruck();
}
public void ResetTruck() {
Name = "Super Truck";
Tires = 4;
}
}
答案 3 :(得分:3)
反思是你的朋友。您可以创建一个帮助方法来使用Activator.CreateInstance()来设置Value类型的默认值,并且' null'对于引用类型,但为什么在PropertyInfo上设置null时烦恼的SetValue也会这样做。
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);
}
}
答案 4 :(得分:2)
关注问题分离(如评论中提到的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();
}
}
对于这样一个简单的类,这当然可能是很多(不需要的)开销,但是在更大/更复杂的项目中它可能是有利的。
这就是关于“最佳”做法的事情......很多时候,没有灵丹妙药,但只有你必须怀疑的建议以及你在特定情况下适用于你的最佳判断。
答案 5 :(得分:0)
您可能需要在私有字段中保存值,以便以后可以恢复它们。也许是这样的:
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;
}
}
答案 6 :(得分:0)
您实际上在寻找State设计模式
答案 7 :(得分:0)
如果你想要一个特定的过去&#34;状态&#34;您可以创建一个特定的保存点,以便在每次需要时返回。这也让您可以为您创建的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));
}
}
答案 8 :(得分:0)
我用反射解决了类似的问题。您可以使用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));
答案 9 :(得分:0)
如果您不使用会发生冲突的代码生成器或设计器,另一种选择是通过 C# 的 # dummy with date and unix values
df <- data.frame(ts_date = as.Date(c("2021-05-31","2021-06-30","2021-07-31")),
ts_unix = c(1622425615,1625017615,1627696015),
v = c(123, 456, 789))
# used recent unix ts (you could use as.numeric(Sys.time())
end <- as.Date(1627348803/(60*60*24), origin="1970-01-01")
start <- end - 30
# one option to filter data of last thiry
df[df$ts_date >= start & df$ts_date < end,]
ts_date ts_unix v
2 2021-06-30 1625017615 456
library(dplyr)
# dplyr option to filter
df %>%
dplyr::filter(ts_date >= start & ts_date < end)
ts_date ts_unix v
1 2021-06-30 1625017615 456
# dplyr option to filter and using current unix
df %>%
dplyr::filter(ts_unix > as.numeric(Sys.time()) - 30 * 24 * 60 * 60)
ts_date ts_unix v
1 2021-06-30 1625017615 456
2 2021-07-31 1627696015 789
# set up date range
seq(start, end-1, 1)
[1] "2021-06-27" "2021-06-28" "2021-06-29" "2021-06-30" "2021-07-01"
[6] "2021-07-02" "2021-07-03" "2021-07-04" "2021-07-05" "2021-07-06"
[11] "2021-07-07" "2021-07-08" "2021-07-09" "2021-07-10" "2021-07-11"
[16] "2021-07-12" "2021-07-13" "2021-07-14" "2021-07-15" "2021-07-16"
[21] "2021-07-17" "2021-07-18" "2021-07-19" "2021-07-20" "2021-07-21"
[26] "2021-07-22" "2021-07-23" "2021-07-24" "2021-07-25" "2021-07-26"
内容,它类似于反射,但意味着向类添加比反射更多的元信息反射可以。
TypeDescriptor
请注意,如果存在,ResetValue 也会重置为阴影属性。 the docs 中解释了选择哪个选项的优先级:
<块引用>此方法按以下优先顺序确定要将属性重置为的值: