2010-07-17 6 views
13

Ho un semplice tipo di valore:Serializzazione risultato di un 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); 
     } 
    } 

che, come si noterà è serializzabile. Poi ho un elenco di questi:

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

e un metodo LINQ per eliminare la parte inferiore del 5% e il top 5% di timer dalla lista:

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

Ho quindi sto cercando di Seralize in XML il risultato di questa enumerazione, cioè serializzare solo i valori dei temporizzatori del mezzo 90%, eliminando la parte superiore e inferiore 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()); 
} 

il problema è che quando questo codice viene eseguito, ottengo questo:

Una prima eccezione di possibilità di tipo 'System.Runtime.Serialization.SerializationException' verificato in mscorlib.dll Microsoft.WindowsAzure.ServiceRuntime Critici: 1: eccezione non gestita: System.Runtime.Serialization.SerializationException: Digitare 'System.Linq.Enumerable + d__3a`1 [[TracePerfWorker.TraceTimer + TimerInstance, TracePerfWorker, Versione = 1.0.0.0, Cultura = neutra, PublicKeyToken = null]]' in Assembly 'System.Core, Versione = 4.0. 0.0, Culture = neutro, PublicKeyToken = b77a5c561934e089 'non è contrassegnato come serializzabile . a System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers (RuntimeType tipo) a System.Runtime.Serialization.FormatterServices.GetSerializableMembers (Tipo tipo, contesto StreamingContext) a System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() a System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize (Object obj , ISurrogateSelector surrogateSelector, contesto StreamingContext, serObjectInfoInit serObjectInfoInit, convertitore IFormatterConverter, ObjectWriter objectWriter, SerializationBinder legante) a System.Runtime.Serialization. Formatters.Binary.WriteObjectInfo.Serialize (oggetto obj, ISurrogateSelector surrogateSelector, contesto StreamingContext, SerObjectInfoInit serObjectInfoInit, convertitore IFormatterConverter, ObjectWriter objectWriter, SerializationBinder legante) a System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize (Object grafico, Header [] inHeaders, __BinaryWriter serWriter , booleano FVerificare) a System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (stream serializationStream, oggetto grafico, intestazioni Header [], Boolean FVerificare) a System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (Stream serializationStream, Object graph) su TracePerfWorker.TraceTimer.SerializeTimersToStream (Stream s) in c: \ Users \ M ike \ Documenti \ Visual Studio 2010 \ Projects \ AzureTracePerfTest \ TracePerfWorker \ TraceTimer.cs: linea 88 a TracePerfWorker.WorkerRole.SerializeTimersToBlob (String strTimerGroupName) in C: \ Users \ Mike \ Documenti \ Visual Studio 2010 \ Projects \ AzureTracePerfTest \ TracePerfWorker \ WorkerRole.cs: riga in TracePerfWorker.WorkerRole.DoWorkNoTrace() in c: \ Users \ Mike \ Documents \ Visual Studio 2010 \ Projects \ AzureTracePerfTest \ TracePerfWorker \ WorkerRole.cs: Linea a TracePerfWorker.WorkerRole.Run() in C: \ Users \ Mike \ Documenti \ Visual Studio 2010 \ Projects \ AzureTracePerfTest \ TracePerfWorker \ WorkerRole.cs: linea 77 a Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment .StartRoleInternal() a Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.StartRole() a Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader.RoleRuntimeBridge.b__1() a System.Threading.ThreadHelper.ThreadStart_Context (stato oggetto) presso System .Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) in System.Threading.ExecutionContext.Run (Esegui ExecutionContext nContext, ContextCallback callback, Object state) a System.Threading.ThreadHelper.ThreadStart()

penso ottengo ciò che questo mi sta dicendo - la classe implicita che l'enumeratore ha apparentemente generato ('System.Linq. Enumerable + d__3a`1 [[TracePerfWorker.TraceTimer + TimerInstance, TracePerfWorker ') non è contrassegnato come serializzabile.

Ma questa sembra una situazione molto comune, dove sto prendendo un tipo di valore serializable (TimerInstance), e solo la costruzione di una query LINQ su un elenco di questi valori, vale a dire l'enumeratore è solo la restituzione di valori TimerInstance - come faccio quindi a convincerlo che ciò che l'enumeratore sta restituendo è solo un elenco di valori di TimerInstance, che sono serializzabili?

risposta

15

Che tipo di utilizzo di ToList per ottenere un elenco di elementi prima di chiamare serializzare? Il tuo metodo dovrà essere modificato per restituire un List<TimerInstance> invece di IEnumerable<TimerInstance>

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

+4

In realtà, il tipo di metodo di ritorno può rimanere come 'IEnumerable '. Basta aggiungere il 'ToList' è sufficiente. –

+0

Grazie. Questo è stato. –

+0

ToList() ha risolto anche il mio problema: var timestamp = (da t in Enumerable.Range (1, chunk_samples) .Reverse() selezionare ora - t/sampling_rate) .ToList(); –