开发者

How to serialize System.Diagnostics.Stopwatch

I have a class that is marked [Serializable] which contains a System.Diagnostics.Stopwatch member; however I cannot serialize the class using BinaryFormatter becau开发者_开发百科se of the System.Diagnostics.Stopwatch. Is there a way to mark or make System.Diagnostics.Stopwatch serializable ?


You could mark the Stopwatch member with NonSerializedAttribute. This way it will be excluded from the serialization process and the containing class will be successfully serialized.

[NonSerialized]
public Stopwatch watch;


You can create a SerializationSurrogate and a SurrogateSelector for the StopWatch.

Be mindful that the StopWatch class may have machine specific state, i.e. the tick frequency and the like. So when you serialize, check the Serialization context that the serialization is not intended for cross machine usage (if you intend to copy all the values), or create a completly new instance with only the timing data.

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();
    }
}


Try creating a serializable wrapper object for the stopwatch.

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

More info on ISerializable..


You can't make Stopwatch serializable, but if you really wish to serialize it (however you might want to do that), your containing class can implement ISerializable.

In this case, you must provide the custom logic for serializing and deserializing the Stopwatch.

How you will manage to serialize a running Stopwatch in a meaningful way is beyond me, however.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜