Сериализация результата LINQ IEnumerable

У меня есть простой тип значения:

    [Serializable]
    private struct TimerInstance
    {
        public TimerInstance(string str, long nTicks)
        {
            _name = str;
            _ticks = nTicks;
        }

        private readonly string _name;
        private readonly long _ticks;

        public string Name { get { return _name; } }
        public long Ticks { get { return _ticks; } }

        public override string ToString()
        {
            return string.Format("{0,20}: {1,10:N}", Name, Ticks);
        }
    }

который, как вы заметите, сериализуется. Тогда у меня есть список из них:

static private List<TimerInstance> _Timers = new List<TimerInstance>();

и метод LINQ, чтобы исключить нижние 5% и верхние 5% таймеров из списка:

// Return items that should be persisted.  By convention, we are eliminating the "outlier"
// values which I've defined as the top and bottom 5% of timer values.
private static IEnumerable<TimerInstance> ItemsToPersist()
{
    // Eliminate top and bottom 5% of timers from the enumeration.  Figure out how many items
    // to skip on both ends.
    int iFivePercentOfTimers = _Timers.Count / 20;
    int iNinetyPercentOfTimers = _Timers.Count - iFivePercentOfTimers * 2;

    return (from x in _Timers
            orderby x.Ticks descending
            select x).Skip(iFivePercentOfTimers).Take(iNinetyPercentOfTimers);
}

Затем я пытаюсь Seralize to XML получить результат этого перечисления, то есть сериализует только значения таймеров в середине 90%, устраняя верхний и нижний 5%:

// Serialize the timer list as XML to a stream - for storing in an Azure Blob
public static void SerializeTimersToStream(Stream s)
{
    BinaryFormatter f = new BinaryFormatter();
    f.Serialize(s, ItemsToPersist());
}

Проблема в том, что когда этот код выполняется, я получаю следующее:

Первое случайное исключение типа "System.Runtime.Serialization.SerializationException" произошло в mscorlib.dll     Microsoft.WindowsAzure.ServiceRuntime Критический: 1: Необработанное исключение:     System.Runtime.Serialization.SerializationException: Type 'System.Linq.Enumerable + d__3a`1 [[TracePerfWorker.TraceTimer + TimerInstance, TracePerfWorker, Version = 1.0.0.0, Культура = нейтральная, PublicKeyToken = null]] 'в Assembly' System.Core, Version = 4.0.0.0, Культура = нейтральная, PublicKeyToken = b77a5c561934e089 'не отмечена как сериализации.        в System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType тип)        в System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Тип тип, контекст StreamingContext)        в System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()        в System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(объект obj, ISurrogateSelector surrogateSelector, Streaming Контекстный контекст, SerObjectInfoInit serObjectInfoInit, преобразователь IFormatterConverter, ObjectWriter objectWriter, SerializationBinder binder)        в System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, Streaming Контекстный контекст, SerObjectInfoInit serObjectInfoInit, преобразователь IFormatterConverter, ObjectWriter objectWriter, SerializationBinder binder)        в System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(объект graph, Header [] inHeaders, __BinaryWriter serWriter, Boolean fCheck)        в System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(поток serializationStream, граф объектов, заголовки [], Boolean fCheck)        в System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(поток serializationStream, граф объектов)        в TracePerfWorker.TraceTimer.SerializeTimersToStream(поток s) в c:\Users\Mike\Documents\Visual Studio 2010\Projects\AzureTracePerfTest\TracePerfWorker\TraceTimer.cs: строка 88        в TracePerfWorker.WorkerRole.SerializeTimersToBlob(String strTimerGroupName) в c:\Users\Mike\Documents\Visual Studio 2010\Projects\AzureTracePerfTest\TracePerfWorker\WorkerRole.cs: линия 192        в TracePerfWorker.WorkerRole.DoWorkNoTrace() в c:\Users\Mike\Documents\Visual Studio 2010\Projects\AzureTracePerfTest\TracePerfWorker\WorkerRole.cs: линия 153        в TracePerfWorker.WorkerRole.Run() в c:\Users\Mike\Documents\Visual Studio 2010\Projects\AzureTracePerfTest\TracePerfWorker\WorkerRole.cs: строка 77        в Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.StartRoleInternal()        в Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.StartRole()        в Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader.RoleRuntimeBridge.b__1()        в System.Threading.ThreadHelper.ThreadStart_Context (состояние объекта)        в System.Threading.ExecutionContext.Run(ExecutionContext executeContext, обратный вызов ContextCallback, состояние объекта, логическое значение ignoreSyncCtx)        в System.Threading.ExecutionContext.Run(ExecutionContext executeContext, обратный вызов ContextCallback, состояние объекта)        в System.Threading.ThreadHelper.ThreadStart()

Я думаю, что получаю то, что это говорит мне - неявный класс, который, по-видимому, сгенерировал (например, "System.Linq.Enumerable + d__3a`1 [[TracePerfWorker.TraceTimer + TimerInstance, TracePerfWorker" ) сам по себе не является сериализуемым.

Но это похоже на действительно распространенную ситуацию, когда я беру сериализуемый тип значения (TimerInstance) и просто построение LINQ-запроса по списку этих значений, т.е. Перечислитель просто возвращает значения TimerInstance - как я могу затем убедить его, что возвращаемый счетчик представляет собой список значений TimerInstance, которые могут быть сериализованы?

Ответы

Ответ 1

Как использовать ToList для получения списка элементов перед вызовом сериализации? Ваш метод нужно будет изменить, чтобы вернуть List<TimerInstance> вместо IEnumerable<TimerInstance>

http://msdn.microsoft.com/en-us/library/bb342261.aspx