如何在不重新创建新实例的情况下重置实例 Class 的成员?

How to Reset members of an instance Class without recreate a new instance?

我想 Reset 为我的 class 实例 CommunicationErrorsDetails 的所有成员设置默认值。 此 class 是嵌套 class MyNestedClassInstance.

的一部分

这就是我想做的事情:

MyNestedClassInstance.CommunicationErrorsDetails.Reset()

这是我嵌套的示例 class MyNestedClass 哪个实例是 MyNestedClassInstance :

public class MyNestedClass : ICloneable
{
    ...

    /// <summary>
    /// Communication errors count
    /// </summary>
    public class CommunicationErrorsDetailsType : ICloneable
    {
        public int RetryCount;
        public int CRCErrorCount;
        public int DataBytesNotExpectedCount;
        public int TooMuchDataReceivedCount;
        public int ResponseDataAddressNotEqualCount;
        public int BytesReceivedInCommunicationStateStartCount;
        public int BytesReceivedInCommunicationStateSendFrameCount;
        public int BytesReceivedInCommunicationStateDataResponseReceivedCount;
        public int ExceptionCount;
        public int NakcReceivedCount;
        public int AckTimeoutCount;
        public int DataTimeoutCount;
        public double DataTimeoutRate;

        public bool HasCommunicationErrors
        {
            get => RetryCount > 0
                || CRCErrorCount > 0
                || DataBytesNotExpectedCount > 0
                || TooMuchDataReceivedCount > 0
                || ResponseDataAddressNotEqualCount > 0
                || BytesReceivedInCommunicationStateStartCount > 0
                || BytesReceivedInCommunicationStateSendFrameCount > 0
                || BytesReceivedInCommunicationStateDataResponseReceivedCount > 0
                || ExceptionCount > 0
                || NakcReceivedCount > 0
                || AckTimeoutCount > 0
                || DataTimeoutCount > 0;
        }

        public object Clone()
        {
            return MemberwiseClone();
        }

        internal void Reset()
        {
            // ... ?
        }
    }
    public CommunicationErrorsDetailsType CommunicationErrorsDetails = new CommunicationErrorsDetailsType();

    ...
    // Other nested classes
    ...
}

如何实现 Reset() 而不必重新创建新实例并且不必手动重置所有可能属于不同类型的成员?

所有成员都是简单类型(不是 classes)。

此外,我无法更改所有相同类型的 classes 的结构,因为我们有好几年的代码结构都是这样的。

感谢您的帮助。 此致

使用 Reflexion,您可以在 DefaultExpression Class

internal void Reset()
{
    // Retrieves only the fields of this Class
    var bindingFlags = BindingFlags.Instance
                       | BindingFlags.NonPublic
                       | BindingFlags.Public;
    List<FieldInfo> members = this.GetType()
                                  .GetFields(bindingFlags)
                                  .Where(f => f.MemberType == MemberTypes.Field)
                                  .Where(value => value != null)
                                  .ToList();

    // Set all fields to its default type value
    for (int i = 0; i < members.Count(); i++)
    {
        // This expression represents the default value of a type
        // (0 for integer, null for a string, etc.)
        Expression defaultExpr = Expression.Default(typeof(byte));
        // The following statement first creates an expression tree,
        // then compiles it, and then executes it.
        var defaultValue = Expression.Lambda<Func<byte>>(defaultExpr).Compile()();
        // Set the default value
        members[i].SetValue(this, defaultValue);
    }
}

只是提供另一个想法。使用间接寻址。

class Instance
{
    public Holder<int> IntValue1;
    public Holder<int> IntValue2;
    public Holder<double> DoubleValue1;

    public void Reset()
    {
        Holder.Reset();
    }

    internal class Holder
    {
        public static event EventHandler OnReset;

        public static void Reset()
        {
            OnReset?.Invoke(null, null);
        }
    }

    public class Holder<T>
    {
        private Holder()
        {
            Holder.OnReset += (_, __) => Value = default(T);
        }

        public T Value { get; set; }

        public static implicit operator T(Holder<T> holder)
        {
            return holder.Value;
        }

        public static implicit operator Holder<T>(T value)
        {
            return new Holder<T>() { Value = value };
        }
    }
}

然后像这样使用它:

instance.IntValue1 = 123;
instance.IntValue2 = 234;
instance.DoubleValue1 = 0.5;

instance.Reset();

如果您同意将 public 字段重新设计为属性(无论如何这是最佳做法),您可以使用内部字典来存储值:

private Dictionary<string, int> _values = new Dictionary<string, int>();

private int get_val(string key) 
{
    int output;
    _values.TryGetValue(key, out output);
    return output;
}

public int RetryCount {get {return get_val("RetryCount");} set {_values["RetryCount"] = value;}
public int CRCErrorCount {get {return get_val("CRCErrorCount");} set {_values["CRCErrorCount"] = value;}
public int DataBytesNotExpectedCount {get {return get_val("CRCErDataBytesNotExpectedCount rorCount");} set {_values["DataBytesNotExpectedCount "] = value;}
...

那么"resetting"一个实例就是一行

internal void Reset() { _values.Clear(); }

一种选择是利用 .NET 中的 struct 可以通过分配 this.

轻松重置自身这一事实

示例代码示例如下(也可在 https://dotnetfiddle.net/zhfjcg 获得)。关键位是:

public void Reset()
{
    this = new TheData();
}

这将重置/重新初始化 TheData 对象 - 这样所有字段都将重置为默认值。

代码示例还使用属性公开 CommunicationErrorsDetailsType 中的结构数据。这不是绝对必要的,但可能是个好主意。

此外,假定 struct 的内容不包含任何具有奇特克隆要求的内容,此技术使克隆 快得多 (与 MemberwiseClone 相比) ,因为将 struct 分配给新变量将 "automatically" 克隆它。

using System;

namespace WhatEver
{
    public struct TheData
    {
        public int RetryCount;
        public int CRCErrorCount;
        public int DataBytesNotExpectedCount;
        public int TooMuchDataReceivedCount;
        public int ResponseDataAddressNotEqualCount;
        public int BytesReceivedInCommunicationStateStartCount;
        public int BytesReceivedInCommunicationStateSendFrameCount;
        public int BytesReceivedInCommunicationStateDataResponseReceivedCount;
        public int ExceptionCount;
        public int NakcReceivedCount;
        public int AckTimeoutCount;
        public int DataTimeoutCount;
        public double DataTimeoutRate;

        public void Reset()
        {
            this = new TheData();
        }
    }

    public class CommunicationErrorsDetailsType
    {
        private TheData data;

        public int DataTimeoutCount
        {
            get
            {
                return data.DataTimeoutCount;
            }
            set
            {
                data.DataTimeoutCount = value;
            }
        }

        public bool HasCommunicationErrors
        {
            get => data.RetryCount > 0
                || data.CRCErrorCount > 0
                || data.DataBytesNotExpectedCount > 0
                || data.TooMuchDataReceivedCount > 0
                || data.ResponseDataAddressNotEqualCount > 0
                || data.BytesReceivedInCommunicationStateStartCount > 0
                || data.BytesReceivedInCommunicationStateSendFrameCount > 0
                || data.BytesReceivedInCommunicationStateDataResponseReceivedCount > 0
                || data.ExceptionCount > 0
                || data.NakcReceivedCount > 0
                || data.AckTimeoutCount > 0
                || data.DataTimeoutCount > 0;
        }

        public object Clone()
        {
            return MemberwiseClone();
        }

        internal void Reset()
        {
            data.Reset();
        }
    }

    public class ToRun
    {
        public static void Main()
        {
            var hereWeGo = new CommunicationErrorsDetailsType();

            hereWeGo.DataTimeoutCount = 4;
            Console.WriteLine(hereWeGo.DataTimeoutCount);
            hereWeGo.Reset();
            Console.WriteLine(hereWeGo.DataTimeoutCount);
        }
    }
}