вторник, 23 октября 2018 г.

Просто взять и сжать массив байтов в C#




К сожалению, .NET имеет API только для сжатия и распаковки потоков данных. А если нужно сжать просто массив байтов в другой массив байтов, приходится использовать внешние библиотеки. Или написать вспомогательный класс, например, такой:

using System.IO;
using System.IO.Compression;
 
namespace Compression
{
    public static class Zip
    {
        public static byte[] Compress(byte[] src)
        {
            using (var input = new MemoryStream(src))
            {
                using (var output = new MemoryStream())
                {
                    using (var compressor = new GZipStream(output, CompressionMode.Compress))
                    {
                        input.CopyTo(compressor);
                    }
                    return output.ToArray();
                }
            }
        }
 
        public static byte[] Decompress(byte[] src)
        {
            using (var input = new MemoryStream(src))
            {
                using (var decompressor = new GZipStream(input, CompressionMode.Decompress))
                {
                    using (var output = new MemoryStream())
                    {
                        decompressor.CopyTo(output);
 
                        return output.ToArray();
                    }
                }
            }
        }
    }
}
 

суббота, 17 февраля 2018 г.

Потокобезопасный Singleton на C#

Написать синглтон, с которым можно быстро и безопасно работать из разных потоков, задача не такая уж и тривиальная, как кажется на первый взгляд. С блокировками это делается довольно просто, например, так:

public class Singleton
{
    private static readonly object syncObj = new object();
    private static volatile Singleton instance;

    public Singleton Shared()
    {
        if (instance == null)
        {
            lock (syncObj)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
        }

        return instance;
    }

    private Singleton()
    {            
    }
    
    // ...
}

Двойная проверка на null нужна для того, чтобы не делать блокировок без необходимости. А если хочется совсем без блокировок? Изучая исходный код пула массивов от майкрософт, нашел реализацию lockfree синглтона. Вот она, очищенная от лишних деталей самого пула:

public class Singleton
{
    private static Singleton instance= null;

    public static Singleton Shared
    {
        get { return Volatile.Read(ref instance) ?? EnsureSharedCreated(); }
    }

    private static Singleton EnsureSharedCreated()
    {
        Interlocked.CompareExchange(ref instance, Create(), null);
        return instance;
    }

    public static Singleton Create()
    {
        return new Singleton();
    }
    
    private Singleton()
    {
    }
    
    // ...
}