2017년 2월 16일 목요일

C#에서의 RAII(Resource Acquisition Is Initialization) idiom 구현

C++에서는 file이나 DB의 resoruce leak 처리를 위해서
RAII idiom을 자주 사용하곤 했었는데,

http://en.cppreference.com/w/cpp/language/raii
https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization

#include <mutex>
#include <iostream>
#include <string> 
#include <fstream>
#include <stdexcept>

void write_to_file (const std::string & message) {
    // mutex to protect file access (shared across threads)
    static std::mutex mutex;

    // lock mutex before accessing file
    std::lock_guard<std::mutex> lock(mutex);

    // try to open file
    std::ofstream file("example.txt");
    if (!file.is_open())
        throw std::runtime_error("unable to open file");
    
    // write message to file
    file << message << std::endl;
    
    // file will be closed 1st when leaving scope (regardless of exception)
    // mutex will be unlocked 2nd (from lock destructor) when leaving
    // scope (regardless of exception)
}

C#에서는 destructor 사용에 신중해져야 해서
찾아보니 다음과 같은 글들이 있어 링크함.


요약하면 
- IDisposable 인터페이스를 구현하고
- 객체를 항상 삭제하는 using 문을 이용하여 RAII 객체를 사용하라는 것


MSDN의 IDisposable 설명에서도 언급하고 있다.

IDisposable을 구현 하는 개체를 사용 하 여

앱이 IDisposable 인터페이스를 구현 하는 개체를 사용 하는 경우 개체의 IDisposable.Dispose 구현을 사용 하는 경우 해당 개체의 구현을 호출 해야 합니다. 프로그래밍 언어에 따라 두 가지 방법 중 하나에서이 수행할 수 있습니다.

  • 및 Visual Basic에서 C# using 문과 같은 언어 구문을 사용 합니다.

  • try/finally 블록에 IDisposable.Dispose 구현에 대 한 호출을 래핑합니다.




RAII (Resource Acquisition Is Initialization) C# Helper Classes 예제
https://www.codeproject.com/Articles/122129/RAII-Resource-Acquisition-Is-Initialization-C-Help

using (var objGuard = new RAIIGuard&lt;int>(
                  () =>objStack.Pop(),
                  (e)=>objStack.Push(e)))
{
    ...
    if (objGuard.Item != 0)
    {
        return;
    }   
    ...
    if (...)
    {
         throw new ...;
    }
    ...
}



// used for symmetric actions like login, logout
public sealed class RAIIGuard: IDisposable
{
    private Action Cleanup { get; set; }
    public RAIIGuard(Action init, Action cleanup)
    {
        Cleanup = cleanup;
        if (init != null) init();
    }
    void IDisposable.Dispose() { if (Cleanup != null) Cleanup(); }
]
// used for symmetric actions that must pass
// over an object from init to cleanup and that
// need to provide the item to the "using" body
public sealed class RAIIGuard&lt;T>: IDisposable
{
    private Action&lt;T> Cleanup { get; set; }
    public T Item { get; private set; }
    public RAIIGuard(Func&lt;T> init, Action&lt;T> cleanup)
    {
        Cleanup = cleanup;
        Item = (init != null) ? init() : default(T);
    }
    void IDisposable.Dispose() { if (Cleanup != null) Cleanup(Item); }
]



Resource Acquisition is Initialization in C#
http://geekswithblogs.net/codeWithoutFear/archive/2012/06/28/raii-in-csharp.aspx

Here is a class and sample that combines a few features of C# to provide an RAII-like solution:

using System;

namespace RAII
{
    public class DisposableDelegate : IDisposable
    {
        private Action dispose;

        public DisposableDelegate(Action dispose)
        {
            if (dispose == null)
            {
                throw new ArgumentNullException("dispose");
            }

            this.dispose = dispose;
        }

        public void Dispose()
        {
            if (this.dispose != null)
            {
                Action d = this.dispose;
                this.dispose = null;
                d();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.Out.WriteLine("Some resource allocated here.");

            using (new DisposableDelegate(() => Console.Out.WriteLine("Resource deallocated here.")))
            {
                Console.Out.WriteLine("Resource used here.");

                throw new InvalidOperationException("Test for resource leaks.");
            }
        }
    }
}

The output of this program is:

Some resource allocated here.
Resource used here.

Unhandled Exception: System.InvalidOperationException: Test for resource leaks.
   at RAII.Program.Main(String[] args) in c:\Dev\RAII\RAII\Program.cs:line 40
Resource deallocated here.







댓글 없음:

댓글 쓰기