Ответ 1
Как использовать ToList для получения списка элементов перед вызовом сериализации?
Ваш метод нужно будет изменить, чтобы вернуть List<TimerInstance>
вместо IEnumerable<TimerInstance>
У меня есть простой тип значения:
[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, которые могут быть сериализованы?
Как использовать ToList для получения списка элементов перед вызовом сериализации?
Ваш метод нужно будет изменить, чтобы вернуть List<TimerInstance>
вместо IEnumerable<TimerInstance>