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 구현을 사용 하는 경우 해당 개체의 구현을 호출 해야 합니다. 프로그래밍 언어에 따라 두 가지 방법 중 하나에서이 수행할 수 있습니다.
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<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<T>: IDisposable
{
private Action<T> Cleanup { get; set; }
public T Item { get; private set; }
public RAIIGuard(Func<T> init, Action<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.aspxHere 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.