-- Listing 16.12

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlTypes;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.Server;
namespace Helion.Examples {
   [Serializable]
   [Microsoft.SqlServer.Server.SqlUserDefinedAggregate (
      Format.UserDefined,
      IsNullIfEmpty = true,
      MaxByteSize = -1 )]
   [StructLayout(LayoutKind.Sequential)]
   public struct Median : IBinarySerialize
   {
      List<double> temp; // Lista liczb.
      public void Init()
      {
         // Utwrz now list liczb typu double.
         this.temp = new List<double>();
      }
      public void Accumulate(SqlDouble number)
      {
         if (!number.IsNull) // Pomi wartoci NULLs.
         {
            this.temp.Add(number.Value); // Jeli liczba jest rna od NULL, dodaj j do listy.
         }
      }
      public void Merge(Median group)
      {
         // Pocz dwa zestawy liczb.
         this.temp.InsertRange(this.temp.Count, group.temp);
      }
      public SqlDouble Terminate() {
         SqlDouble result = SqlDouble.Null; // Domylny wynik to NULL.
         this.temp.Sort(); // Posortuj list liczb.
         int first, second; // Indeksy dwch rodkowych liczb.
         if (this.temp.Count % 2 == 1)
         {
            // Przy nieparzystej liczbie liczb we liczb rodkow dwukrotnie.
            first = this.temp.Count / 2;
            second = first;
         }
         else
         {
            // Przy parzystej liczbie liczb we dwie rodkowe liczby.
            first = this.temp.Count / 2 - 1;
            second = first + 1;
         }
         if (this.temp.Count > 0) // Jeli s liczby, oblicz median.
         {
            // Oblicz median jako redni dwch rodkowych liczb.
            result = (SqlDouble)( this.temp[first] + this.temp[second] ) / 2.0;
         }
         return result;
      }
      #region IBinarySerialize Members
      // Wasna metoda do wczytywania serializowanych danych.
      public void Read(System.IO.BinaryReader r)
      {
         // Utwrz now list wartoci typu double.
         this.temp = new List<double>();
         // Pobierz liczb wartoci poddanych serializacji.
         int j = r.ReadInt32();
         // W ptli dodaj wszystkie serializowane wartoci do listy.
         for (int i = 0; i < j; i++)
         {
            this.temp.Add(r.ReadDouble());
         }
      }
      // Wasna metoda do zapisywania serializowanych danych.
      public void Write(System.IO.BinaryWriter w)
      {
         // Zapisz liczb wartoci na licie.
         w.Write(this.temp.Count);
         // Zapisz wszystkie wartoci z listy.
         foreach (double d in this.temp)
         {
            w.Write(d);
         }
      }
      #endregion
   }
}
