Skip to content

Instantly share code, notes, and snippets.

@atifaziz
Created April 27, 2009 10:12
Show Gist options
  • Save atifaziz/102424 to your computer and use it in GitHub Desktop.
Save atifaziz/102424 to your computer and use it in GitHub Desktop.
// Compile using:
// csc /target:winexe /noconfig /define:DEBUG FinalizerDemo.cs /r:System.dll /r:System.Windows.Forms.dll
// Self-contained demonstration code for:
// http://stackoverflow.com/questions/792660/is-gc-suppressfinalize-guaranteed
using WikiPad;
using System;
using System.Windows.Forms;
public class Program
{
public static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form();
var button = new Button
{
Text = "Work, baby, work!",
Dock = DockStyle.Fill
};
button.Click += delegate
{
if (args.Length > 0 && args[0].Equals("notusing", StringComparison.OrdinalIgnoreCase))
{
CurrentCursorScope.EnterWait(); // the wrong way that will
System.Threading.Thread.Sleep(1000); // trigger warning on exit
}
else
{
using (CurrentCursorScope.EnterWait()) // the right way
System.Threading.Thread.Sleep(1000);
}
};
form.Controls.Add(button);
Application.Run(form);
GC.WaitForPendingFinalizers();
}
}
#region License, Terms and Author(s)
//
// Schnell - Wiki widgets
// Copyright (c) 2007 Atif Aziz. All rights reserved.
//
// Author(s):
// Atif Aziz, http://www.raboof.com
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#endregion
namespace WikiPad
{
#region Imports
using System;
using System.Diagnostics;
#endregion
//
// NOTE: To use SingletonScope and ISingletonScopeHelper with value
// types, use Nullable<T>. For example, if the type of value to scope
// is ThreadPriority then use ISingletonScopeHelper<ThreadPriority?>
// and SingletonScope<ThreadPriority?>.
//
//
// In debug builds, this type is defined as a class so a finalizer
// can be used to detect an undisposed scope.
//
/// <summary>
/// Designed to change a singleton and scope that change. After exiting
/// the scope, the singleton is restored to its value prior to entering
/// the scope.
/// </summary>
#if !DEBUG
internal struct SingletonScope<T, H>
#else
internal sealed class SingletonScope<T, H>
#endif
: IDisposable
where H : ISingletonScopeHelper<T>, new()
{
private T _old;
public SingletonScope(T temp)
{
_old = Helper.Install(temp);
}
private static H Helper
{
get { return new H(); }
}
public void Dispose()
{
//
// First, transfer fields to stack then nuke the fields.
//
T old = _old;
//
// Already disposed?
//
if (old == null)
return;
_old = default(T);
//
// Shazam! Restore the old value.
//
Helper.Restore(old);
#if DEBUG
GC.SuppressFinalize(this); // Only when defined as a class!
#endif
}
#if DEBUG
//
// This finalizer is used to detect an undisposed scope. This will
// only indicate that the scope was not disposed but (unfortunately)
// not which one and where since GC will probably collect much later
// than it should have been disposed.
//
~SingletonScope()
{
Debug.Fail("Scope for " + typeof(T).FullName + " not disposed!");
}
#endif
}
}
#region License, Terms and Author(s)
//
// Schnell - Wiki widgets
// Copyright (c) 2007 Atif Aziz. All rights reserved.
//
// Author(s):
// Atif Aziz, http://www.raboof.com
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#endregion
namespace WikiPad
{
/// <summary>
/// Provides helper implementation to SingletonScope for installing
/// and restoring the singleton value.
/// </summary>
internal interface ISingletonScopeHelper<T>
{
T Install(T temp);
void Restore(T old);
}
}
#region License, Terms and Author(s)
//
// Schnell - Wiki widgets
// Copyright (c) 2007 Atif Aziz. All rights reserved.
//
// Author(s):
// Atif Aziz, http://www.raboof.com
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#endregion
namespace WikiPad
{
#region Imports
using System.Windows.Forms;
#endregion
internal static class CurrentCursorScope
{
public static SingletonScope<Cursor, Helper> EnterWait()
{
return Enter(Cursors.WaitCursor);
}
public static SingletonScope<Cursor, Helper> Enter(Cursor cursor)
{
return new SingletonScope<Cursor, Helper>(cursor);
}
internal struct Helper : ISingletonScopeHelper<Cursor>
{
public Cursor Install(Cursor temp)
{
var save = Cursor.Current;
Cursor.Current = temp;
return save;
}
public void Restore(Cursor old)
{
Cursor.Current = old;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment