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<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.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.