如何序列化System.Diagnostics.Stopwatch

时间:2009-12-08 11:23:32

标签: c#

我有一个标记为[Serializable]的类,其中包含一个System.Diagnostics.Stopwatch成员;但是由于System.Diagnostics.Stopwatch,我无法使用BinaryFormatter序列化该类。有没有办法标记或使System.Diagnostics.Stopwatch可序列化?

4 个答案:

答案 0 :(得分:6)

您可以使用NonSerializedAttribute标记秒表成员。这样它将从序列化过程中排除,并且包含类将被成功序列化。

[NonSerialized]
public Stopwatch watch;

答案 1 :(得分:2)

尝试为秒表创建可序列化的包装器对象。

public class SerializableStopwatch : Stopwatch, ISerializable
{
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Ticks", ElapsedTicks);
        // .. etc ..
    }
}

More info on ISerializable ..

答案 2 :(得分:2)

您可以为StopWatch创建SerializationSurrogate和SurrogateSelector。

请注意,StopWatch类可能具有机器特定状态,即刻度频率​​等。因此,在序列化时,请检查序列化上下文,序列化不是用于跨机器使用(如果您打算复制所有值),或者创建仅包含时序数据的完全新实例。

namespace MaLio.StopWatch {
    class Program {
        static void Main(string[] args) {

            Container container = new Container();
            Container copy = null;

            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = 
                new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            // may be a formatter created elsewhere
            if (formatter.SurrogateSelector == null) {
                formatter.SurrogateSelector = new StopWatchSelector();
            }
            else {
                formatter.SurrogateSelector.ChainSelector(new StopWatchSelector());
            }

            using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) {

                formatter.Serialize(stream, container);

                stream.Flush();
                stream.Position = 0;

                copy = formatter.Deserialize(stream) as Container;
            }


            System.Diagnostics.Debug.WriteLine(
                "Reference Equals: " + (object.ReferenceEquals(container, copy)).ToString());

            System.Console.ReadKey();
        }
    }

    public class StopWatchSelector : System.Runtime.Serialization.SurrogateSelector {

        private StopWatchSurrogate _Surrogate;

        public StopWatchSelector() {
            _Surrogate = new StopWatchSurrogate();
        }

        public override System.Runtime.Serialization.ISerializationSurrogate GetSurrogate(
            System.Type type, 
            System.Runtime.Serialization.StreamingContext context,
            out System.Runtime.Serialization.ISurrogateSelector selector) {

            System.Runtime.Serialization.ISerializationSurrogate surrogate;

            surrogate = base.GetSurrogate(type, context, out selector);

            if (surrogate == null) {
                if (type == typeof(System.Diagnostics.Stopwatch)) {
                    surrogate = _Surrogate;
                }
            }

            return surrogate;
        }
    }

    public class StopWatchSurrogate : System.Runtime.Serialization.ISerializationSurrogate {

        private const string NULL_INDICATOR_STRING = @"__StopWatchNull";

        // the invalid contexts as an example
        private const System.Runtime.Serialization.StreamingContextStates INVALID_CONTEXTS =
            System.Runtime.Serialization.StreamingContextStates.CrossMachine | 
            System.Runtime.Serialization.StreamingContextStates.Remoting;

        public void GetObjectData(
            object obj, 
            System.Runtime.Serialization.SerializationInfo info, 
            System.Runtime.Serialization.StreamingContext context) {

            System.Diagnostics.Stopwatch stopWatch = obj as System.Diagnostics.Stopwatch;

            if (stopWatch == null) {
                info.AddValue(NULL_INDICATOR_STRING, true);
            }
            else {
                info.AddValue(NULL_INDICATOR_STRING, false);

                // add other values looked up via reflection
            }
        }

        public object SetObjectData          (
            object obj,
            System.Runtime.Serialization.SerializationInfo info, 
            System.Runtime.Serialization.StreamingContext context, 
            System.Runtime.Serialization.ISurrogateSelector selector) {

            System.Diagnostics.Stopwatch stopWatch = null;
            bool isNull = info.GetBoolean(NULL_INDICATOR_STRING);

            if (!isNull) {
                stopWatch = obj as System.Diagnostics.Stopwatch;
                // read other values and set via reflection
            }

            return stopWatch;
        }

        private void CheckContext(System.Runtime.Serialization.StreamingContext context) {

            if ((context.State & INVALID_CONTEXTS) != 0) {
                throw new System.NotSupportedException();
            }
        }
    }

    [System.Serializable]
    public class Container {

        private System.Diagnostics.Stopwatch _Watch = new System.Diagnostics.Stopwatch();
    }
}

答案 3 :(得分:0)

你不能使秒表可序列化,但如果真的希望序列化它(不过你可能想这样做),你的包含类可以实现ISerializable

在这种情况下,您必须提供用于序列化和反序列化秒表的自定义逻辑。

然而,如何设法以有意义的方式序列化正在运行的秒表是不可能的。