C# 如何重新初始化或重置类的属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/708352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I reinitialize or reset the properties of a class?
提问by Dylan Bennett
I've created a class with properties that have default values. At some point in the object's lifetime, I'd like to "reset" the object's properties back to what they were when the object was instantiated. For example, let's say this was the class:
我创建了一个具有默认值的属性的类。在对象生命周期的某个时刻,我想将对象的属性“重置”回对象被实例化时的状态。例如,假设这是一个类:
public class Truck {
public string Name = "Super Truck";
public int Tires = 4;
public Truck() { }
public void ResetTruck() {
// Do something here to "reset" the object
}
}
Then at some point, after the Name
and Tires
properties have been changed, the ResetTruck()
method could be called and the properties would be reset back to "Super Truck" and 4, respectively.
然后在某些时候,在更改Name
和Tires
属性后,ResetTruck()
可以调用该方法,并且属性将分别重置回“超级卡车”和 4。
What's the best way to reset the properties back to their initial hard-coded defaults?
将属性重置回其初始硬编码默认值的最佳方法是什么?
采纳答案by maxyfc
You can have the initialization in a method instead of inlining with the declaration. Then have the constructor and reset method call the initialization method:
您可以在方法中进行初始化,而不是与声明内联。然后让构造函数和 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;
}
}
Another way is not to have a reset method at all. Just create a new instance.
另一种方法是根本没有重置方法。只需创建一个新实例。
回答by Andy White
You'd probably need to save the values off in private fields, so that they can be restored later. Maybe something like this:
您可能需要将值保存在私有字段中,以便以后可以恢复。也许是这样的:
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;
}
}
回答by Rashack
If you did your initialization in a Reset method you can be good to go:
如果您在 Reset 方法中进行了初始化,则可以很好地进行:
public class Truck {
public string Name;
public int Tires;
public Truck() {
ResetTruck();
}
public void ResetTruck() {
Name = "Super Truck";
Tires = 4;
}
}
回答by Brian Rasmussen
Unless creating the object is really expensive (and Reset isn't for some reason). I see no reason to implement a special reset method. Why don't you just create a new instance with a usable default state.
除非创建对象真的很昂贵(并且重置不是出于某种原因)。我认为没有理由实施特殊的重置方法。为什么不创建一个具有可用默认状态的新实例。
What is the purpose of reusing the instance?
重用实例的目的是什么?
回答by arviman
Reflection is your friend. You could create a helper method to use Activator.CreateInstance() to set the default value of Value types and 'null' for reference types, but why bother when setting null on a PropertyInfo's SetValue will do the same.
反思是你的朋友。您可以创建一个辅助方法来使用 Activator.CreateInstance() 来设置 Value 类型的默认值,并为引用类型设置 '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.
To extend this for your purpose, have private members:
为了您的目的扩展此功能,请拥有私人成员:
//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"};
Set the values in your constructor:
在构造函数中设置值:
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));
}
}
Reset them later:
稍后重置它们:
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);
}
}
回答by Gustavo Mori
Focusing of separation of concerns (like Brian mentioned in the comments), another alternative would be to add a TruckProperties
type (you could even add your default values to its constructor):
关注点分离(如评论中提到的 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;
}
}
Inside your Truck
class, all you would do is manage an instance of the TruckProperties
type, and let it do its reset.
在您的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();
}
}
This certainly may be a lot of (unwanted) overhead for such a simple class, but in a bigger/more complex project it could be advantageous.
对于这样一个简单的类来说,这当然可能是很多(不需要的)开销,但在更大/更复杂的项目中它可能是有利的。
That's the thing about "best" practices... a lot of times, there's no silver bullet, but only recommendations you must take with skepticism and your best judgement as to what applies to you in a particular case.
这就是关于“最佳”实践的事情......很多时候,没有灵丹妙药,只有你必须持怀疑态度接受建议,并在特定情况下对适用于你的情况做出最佳判断。
回答by alex
If you want a specific past "state" of your object you can create a particular save point to return every time you want. This also let you have a diferent state to backup for everey instance that you create. If you class has many properties who are in constant change, this could be your solution.
如果您想要对象的特定过去“状态”,您可以创建一个特定的保存点以在每次需要时返回。这也让您可以为您创建的每个实例备份不同的状态。如果您的班级有许多不断变化的属性,这可能是您的解决方案。
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));
}
}
回答by clamchoda
I solved a similar problem with reflection. You can use source.GetType().GetProperties()
to get a list of all properties which belong to the object.
我用反射解决了类似的问题。您可以使用 source.GetType().GetProperties()
获取属于该对象的所有属性的列表。
Although, this is not always a complete solution. If your object implements several interfaces, you will also get all those properties with your reflection call.
虽然,这并不总是一个完整的解决方案。如果您的对象实现了多个接口,您还将通过反射调用获得所有这些属性。
So I wrote this simple function which gives us more control of which properties we are interested in resetting.
所以我写了这个简单的函数,它让我们可以更好地控制我们有兴趣重置哪些属性。
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.");
}
}
}
And it's use:
它的用途是:
// 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));