I just can't make out if the entity context is disposed in the usage flow when used in a using statement in a web application or a console application.
Thanks!
using System;
using System.Web;
namespace Foo.Model
{
public partial class FooEntities : ObjectContext
{
private const string CurrentContextKey = "FooEntities.Current";
[ThreadStatic]
private static FooEntities _currentOnThreadStatic;
private FooEntities _previousContext;
/// <summary>
/// Gets the current <see cref="FooEntities"/> instance, if an instance can be shared in the current context.
/// </summary>
/// <remarks>
/// The current context is stored in the HTTP context, if it is available (otherwise it is stored in a thread-static instance).
/// Multiple contexts can be stacked.
/// </remarks>
public static FooEntities Current
{
get
{
if (HttpContext.Current != null)
{
return HttpContext.Current.Items[CurrentContextKey] as FooEntities;
}
else
{
return _currentOnThreadStatic;
}
}
private set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[CurrentContextKey] = value;
}
else
{
_currentOnThreadStatic = value;
}
}
}
/// <summary>
/// Returns a repository instance bound to this object context.
/// </summary>
/// <typeparam name="TRepository">The type of repository to instantiate.</typeparam>
/// <returns>The repository instance.</returns>
public TRepository GetRepository<TRepository>()
where TRepository: BaseRepository
{
return (TRepository) Activator.CreateInstance(typeof(TRepository), this);
}
/// <summary>
/// Ensures that an ambient context is available through <see cref="Current"/>, throwing an exception otherwise.
/// </summary>
/// <exception type="InvalidOperationException)">
/// Thrown if <see cref="Current"/> is null.
/// </exception>
public static void EnsureContext()
{
if (Current == null)
{
throw new InvalidOperationException("An ambient FooEntities context is expected.");
}
}
/// <summary>
/// Releases the context instance.
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
Current = _previousContext;
base.Dispose(disposing);
}
/// <summary>
/// Is called by all constructors.
/// </summary>
partial void OnContextCreated()
{
_previousContext = Current;
Current = this;
}
}
}
It is an odd design. As #Joel C points out in his comment you should regard the object context as a shortlived object that you create when you need it and release right afterwards.
But I see no reason that this would leak memory. You are only dealing with managed resources and you are using the same key all the time to the HttpContext so you won't create new objects all over.
Related
I found a project in Unity 5 where python can be run in Unity, and i want to add libraries to it. The trouble is, i can't seem to find where the python libraries from this script. To me, it looks like they're being generated out of thin air. Can i have a pointer as to where this might be coming from? I tried adding it to python path, and its not seeming to work.
using System;
using System.IO;
using System.Linq;
using UnityEngine;
using System.Text;
using System.Collections;
using IronPython.Hosting;
using IronPython.Modules;
using System.Collections.Generic;
using Microsoft.Scripting.Hosting;
/// <summary>
/// Interpreter for IronPython.
/// </summary>
public class Interpreter
{
/// <summary>
/// The scope.
/// </summary>
private ScriptScope Scope;
/// <summary>
/// The engine.
/// </summary>
private ScriptEngine Engine;
/// <summary>
/// The source.
/// </summary>
private ScriptSource Source;
/// <summary>
/// The compiled.
/// </summary>
private CompiledCode Compiled;
/// <summary>
/// The operation.
/// </summary>
private ObjectOperations Operation;
/// <summary>
/// The python class.
/// </summary>
private object PythonClass;
/// <summary>
/// Initializes a new instance of the <see cref="Interpreter"/> class.
/// </summary>
public Interpreter()
{
Engine = Python.CreateEngine();
Scope = Engine.CreateScope();
SetLibrary();
}
/// <summary>
/// Initializes a new instance of the <see cref="Interpreter"/> class.
/// </summary>
/// <param name="source">Source.</param>
public Interpreter(string src) : this()
{
Compile(src);
}
/// <summary>
/// Compile the specified src.
/// </summary>
/// <param name="src">Source.</param>
public string Compile(string src, Microsoft.Scripting.SourceCodeKind CodeKind =
Microsoft.Scripting.SourceCodeKind.SingleStatement)
{
if(src == string.Empty)
return string.Empty;
LoadRuntime();
Source = CodeKind == Microsoft.Scripting.SourceCodeKind.SingleStatement ?
Engine.CreateScriptSourceFromString(src, CodeKind) :
Engine.CreateScriptSourceFromFile(src);
ErrorHandle errors = new ErrorHandle();
MemoryStream stream = new MemoryStream();
//Set IO Ouput of execution
Engine.Runtime.IO.SetOutput(stream, new StreamWriter(stream));
Compiled = Source.Compile(errors);
Operation = Engine.CreateOperations();
try {
Compiled.Execute(Scope);
return FormatOutput(ReadFromStream(stream));
} catch(Exception ex) {
return Engine.GetService<ExceptionOperations>().FormatException(ex);
}
}
/// <summary>
/// Formats the output of execution
/// </summary>
/// <returns>The output.</returns>
/// <param name="output">Output.</param>
private string FormatOutput(string output)
{
return string.IsNullOrEmpty(output) ? string.Empty
: string.Join("\n", output.Remove(output.Length-1)
.Split('\n')
.Reverse().ToArray());
}
/// <summary>
/// Reads MemoryStream.
/// </summary>
/// <returns>The from stream.</returns>
/// <param name="ms">Ms.</param>
private string ReadFromStream(MemoryStream ms) {
int length = (int)ms.Length;
Byte[] bytes = new Byte[ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Read(bytes, 0, length);
return Encoding.GetEncoding("utf-8").GetString(bytes, 0, length);
}
/// <summary>
/// Set sys paths
/// </summary>
private void SetLibrary()
{
if(PythonBase.SysPath.Count > 0) {
ICollection<string> SysPath = Engine.GetSearchPaths();
foreach(string path in PythonBase.SysPath)
SysPath.Add(path);
Engine.SetSearchPaths(SysPath);
}
}
/// <summary>
/// Load runtime Assemblies of Unity3D
/// </summary>
private void LoadRuntime()
{
Engine.Runtime.LoadAssembly(typeof(GameObject).Assembly);
}
public void AddRuntime<T>()
{
Engine.Runtime.LoadAssembly(typeof(T).Assembly);
}
public void AddRuntime(Type type)
{
Engine.Runtime.LoadAssembly(type.Assembly);
}
/// <summary>
/// Gets the variable or class
/// </summary>
/// <returns>The variable.</returns>
/// <param name="name">Name.</param>
public object GetVariable(string name)
{
return Operation.Invoke(Scope.GetVariable(name));
}
/// <summary>
/// Calls the method.
/// </summary>
/// <param name="name">Name.</param>
public void InvokeMethod(object nameClass, string Method, params object[] parameters)
{
object output = new object();
if(Operation.TryGetMember(nameClass, Method, out output)) {
object Func = Operation.GetMember(nameClass, Method);
Operation.Invoke(Func, parameters);
}
}
}
I have a my SQLiteOpenHelper class, which is written as a singleton. I should note that I am not doing this in Java, I am using Xamarin.Android C# to write this.
Here's a snippet from that class:
public class DatabaseHelper : SQLiteOpenHelper
{
private static readonly string TAG = typeof(DatabaseHelper).FullName;
private static readonly string _databaseName = "istockdb";
private static readonly int _databaseVersion = 32;
private static DatabaseHelper _instance;
private Context _context;
private DatabaseHelper(Context context) : base(context, _databaseName, null, _databaseVersion)
{
_context = context;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static DatabaseHelper Instance(Context context)
{
// *** Use the application context, which will ensure that ***
// *** the Activity's context is not accidentally leaked ***
return _instance ?? (_instance = new DatabaseHelper(context.ApplicationContext));
}
}
So I have my DatabaseHelper that is a singleton and is used like this within Activities and Services:
Service:
[Service(Name=Text.MobileBackgroundHbService, Enabled = true, Exported = true), IntentFilter(new []{Intents.SyncHeartbeats})]
public class BGHeartbeatService : BaseIntentService
{
public BGHeartbeatService()
{
this._database = DatabaseHelper.Instance(Application.Context);
}
protected override void OnHandleIntent(Intent intent)
{
if (this._database == null)
this._database = DatabaseHelper.Instance(Application.Context);
if (intent.Action.Equals(Intents.SyncHeartbeats)) SyncHeartbeatRecords();
var broadcastIntent = new Intent(Intents.MobileRefresh);
SendBroadcast(broadcastIntent);
}
}
Activity, actually a BaseActivity which all Activities inherit from:
[Activity(Label = "BaseActivity")]
public abstract class BaseActivity : AppCompatActivity
{
/// <summary>
/// Reference to the current context.
/// </summary>
protected Context _context { get; set; }
/// <summary>
/// "Tag" used for Log functionallity.
/// </summary>
protected string _tag { get; set; }
/// <summary>
/// Reference To <see cref="RemoteSyncServiceConnection"/>
/// </summary>
protected RemoteSyncServiceConnection _service_connection;
/// <summary>
/// Reference To The Current SessionState.
/// </summary>
protected SessionState _session_state;
/// <summary>
/// Reference To <see cref="SyncReceiver"/>
/// </summary>
protected SyncReceiver _sync_receiver;
/// <summary>
/// Base FloatingActionButton.
/// </summary>
protected FloatingActionButton _base_fab;
/// <summary>
/// Is the Fab Menu Shown / Hid.
/// </summary>
protected static bool _is_fab_open;
protected IConnection _printer_connection;
protected string _printer_address;
protected bool _service_required;
protected bool _receiver_required;
protected MediaPlayer _media_player;
protected DatabaseHelper _database;
/// <summary>
/// <see cref="IntentFilter"/> for the <see cref="SyncReceiver"/>
/// </summary>
protected readonly string[] _intent_filters =
{
Intents.AlarmCompleteOrders,
Intents.AlarmHeartbeats,
Intents.AlarmPkas,
Intents.AlarmTrackingScans,
Intents.MobileRefresh
};
#region Lifecycle Methods
/// <summary>
/// Application Lifecycle Method.
/// </summary>
/// <param name="savedInstanceState"></param>
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// *** Initialize Xamarin.Essentials ***
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// *** Initialize the DatabaseHelper ***
if(this._database == null)
this._database = DatabaseHelper.Instance(this.ApplicationContext);
}
}
The DatabaseHelper instance is being disposed of frequently causing either services, or activities to try and access the disposed _database object.
How is this being disposed of and why?
I thought making the _instance static within the DatabaseHelper as well as making the constructor private and forcing the use of the DatabaseHelper.Instance method would keep a single instance of the DatabaseHelper that wouldn't be disposed of between activities and services?
Am I misunderstanding this?
EDIT logcat output from try/catch blocks showing the exception being thrown. The SaveHeartbeat method exists in the base activity.:
protected void SaveHeartbeat(DateTime time, string sourceActivity, [CallerMemberName] string sourceEvent = "")
{
try
{
var heartbeat = new SmartWarehouse.Shared.Models.Heartbeat(sourceActivity,
sourceEvent,
this._session_state.CurrentSession.ROWID.ToString());
this._database.InsertHeartbeat(heartbeat);
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
}
EDIT 2 DatabaseHelper.InsertHeartbeat():
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
Alright so my theory is that when I access the db object in the using() statement it is disposing of the database that the DatabaseHelper object uses. Also noticed that I'm not using db.InsertOrThrow() method which I should be.. Gonna do some re-working on my DatabaseHelper class to see if that resolves the issue.
It turns out that my singleton instance of the DatbaseHelper was not being disposed of.
Actually what was happening is I was disposing of the SQLiteDatabase object that was being used by the DatbaseHelper from within the helper methods.
All I had to do to actually resolve the issue was change:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This using() statement is causing the disposal
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
TO:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This is no longer initialized in a using() statement
var db = this.WritableDatabase;
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
SUMMARY:
By initializing my SQLiteDatabase db object inside of using() statements inside of my helper methods I was disposing of the SQLiteDatabase that my DatabaseHelper needed.
I found this code and it looks like a fixed version of the C# version of FileSystemWatcher from Microsoft. However the problem is that I have no idea how to use or run it. Could someone with some expertise please shed some light for me? How do I use this code?
The original source and explanation is here I believe. I've tried to contact the originator but I cannot get a response.
http://fascinatedwithsoftware.com/blog/post/2012/12/30/How-to-Use-FileSystemWatcher-Instead-of-Polling.aspx
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Threading;
namespace Fws.Collections
{
/// <summary>
/// Detects the arrival of files in a directory and makes them available to a client class
/// as an IEnumerable of fully pathed file names. Unlike the .NET FileSystemWatcher, this
/// class yields files that exist when the object is constructed. Also, it is not an IDisposable.
/// </summary>
/// <remarks>
/// <para>
/// If a file arrives during the execution of this class's constructor, it may be reported more than
/// once. Also, some programs write their files in such a way that the underlying FileSystemWatcher
/// will fire a Create event more than once. In those cases, this class will yield the
/// file multiple times.
/// </para><para>
/// Client code must account for these possibilities. It is envisioned that wrapping classes may
/// refine the yielded files by waiting for them to quiesce, filtering out duplicates, etc.
/// </para>
/// <para>
/// This class is thread-safe: more than one thread may enumerate the files presented by a
/// single instance of this class, and each thread will get all the files.
/// </para>
/// </remarks>
public sealed class CreatedFileCollection : IEnumerable<string>
{
#region Fields
readonly string _directory;
readonly string _filePattern;
readonly CancellationToken _cancellationToken;
#endregion
#region Nested Class to Collect Results
/// <summary>
/// A queue of files found within one GetEnumerator call.
/// </summary>
private sealed class CreatedFileQueue : IDisposable
{
readonly ConcurrentQueue<string> _queue = new ConcurrentQueue<string>();
readonly SemaphoreSlim _fileEnqueued = new SemaphoreSlim(0);
/// <summary>
/// Attempt to get a file from the queue.
/// </summary>
/// <param name="fileName">The name of the file, if one is immediately available.</param>
/// <returns>True if got a file; false if not.</returns>
public bool TryDequeue(out string fileName, CancellationToken cancellationToken)
{
fileName = null;
// Avoid the OperationCanceledException if we can.
if (cancellationToken.IsCancellationRequested)
return false;
try
{
_fileEnqueued.Wait(cancellationToken);
return _queue.TryDequeue(out fileName);
}
catch (OperationCanceledException)
{
return false;
}
}
/// <summary>
/// Handles the Created event of the enclosing class's FileSystemWatcher.
/// </summary>
/// <param name="sender">This object.</param>
/// <param name="e">Args for the new file.</param>
public void FileCreated(object sender, FileSystemEventArgs e)
{
_queue.Enqueue(e.FullPath);
_fileEnqueued.Release();
}
public void Dispose()
{
_fileEnqueued.Dispose();
}
}
#endregion
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
/// <param name="cancellationToken">This class will terminate the enumeration of
/// files when and only when the token enters the canceled state.</param>
/// <param name="directory">The directory to watch.</param>
/// <param name="filePattern">A pattern to match in the file name. Example: "*.txt".
/// Null means all files.</param>
/// <remarks>Duplicates may be returned on the queue. See remarks for the class.</remarks>
public CreatedFileCollection(CancellationToken cancellationToken, string directory, string filePattern=null)
{
Contract.Requires(directory != null);
Contract.Requires(cancellationToken != null);
if (!Directory.Exists(directory))
throw new ArgumentException(String.Format("Directory '{0}' does not exist.", directory));
_directory = directory;
_filePattern = filePattern ?? "*";
_cancellationToken = cancellationToken;
}
#endregion
#region Methods
/// <summary>
/// Get an enumerator that will yield files until the CanellationToken is canceled.
/// </summary>
/// <returns>Fully pathed file names.</returns>
/// <remarks>
/// It is possible for a file name to be returned from more than once.
/// </remarks>
public IEnumerator<string> GetEnumerator()
{
if (!_cancellationToken.IsCancellationRequested)
{
using (var watcher = new FileSystemWatcher(_directory, _filePattern))
{
using (var queue = new CreatedFileQueue())
{
// Restrict the NotifyFilter to all that's necessary for Create events.
// This minimizes the likelihood that FileSystemWatcher's buffer will be overwhelmed.
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Created += queue.FileCreated;
watcher.EnableRaisingEvents = true;
// Note that if a file arrives during the following loop, it will be placed on the queue
// twice: once when the Create event is raised, and once by the loop itself.
foreach (var file in Directory.GetFiles(_directory, _filePattern, SearchOption.TopDirectoryOnly))
{
queue.FileCreated(this, new FileSystemEventArgs(WatcherChangeTypes.Created, _directory, Path.GetFileName(file)));
}
if (!_cancellationToken.IsCancellationRequested)
{
string fileName;
while (queue.TryDequeue(out fileName, _cancellationToken))
yield return fileName;
}
}
}
}
}
/// <summary>
/// Required method for IEnumerable.
/// </summary>
/// <returns>The generic enumerator, but as a non-generic version.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}
Here is an example I knocked up which seems to work.
public static void Main()
{
var watcher = new CreatedFileCollection(CancellationToken.None, "c:\\test");
var enumerator = watcher.GetEnumerator();
Task.Run(() =>
{
//This will block until either a new file is created or the
//passed CancellationToken is cancelled.
while (enumerator.MoveNext())
{
Console.WriteLine("New File - " + enumerator.Current);
}
});
Console.ReadLine();
}
This will print a line for all files that are created while the program is running.
So we have two Eventhandlers listening to the same event.
A decorator is supposed to create a LifteTimeScope, resolve the decorated eventhandler and invoke the Handle method of the decorated eventhandler.
I found lot of examples of doing this with CommandHandlers. But there its easier since there is only one Handler per Command. Not many.
So the Question is how to register the event handlers and the decorator in autofac!
class EventHandlerA : IAsyncNotification<AnEvent>
{
public void Handle(AnEvent theEvent)
{
}
}
class EventHandlerB : IAsyncNotification<AnEvent>
{
public void Handle(AnEvent theEvent)
{
}
}
/// <summary>
/// Wraps inner Notification Handler in Autofac Lifetime scope named
PerEventHandlerScope"
/// </summary>
/// <typeparam name="TNotification"></typeparam>
public class LifetimeScopeEventHandlerDecorator<TNotification> :
IAsyncNotificationHandler<TNotification> where TNotification : class,
IAsyncNotification
{
private readonly ILifetimeScope _scope;
private readonly Type _decoratedType;
/// <summary>
/// Const Name of Scope that dependencies can Match using
PerMatchingLifeTimeScope(LifetimeScopeEventHandlerDecorator.ScopeName)
/// </summary>
public const string ScopeName = LifeTimeScopeKeys.PerHandlerKey;
/// <summary>
/// constructor
/// </summary>
/// <param name="scope"></param>
public LifetimeScopeEventHandlerDecorator( ILifetimeScope scope, Type
decoratedType )
{
_decoratedType = decoratedType;
_scope = scope;
}
/// <summary>
/// Wraps inner Notification Handler in Autofac Lifetime scope
/// </summary>
/// <param name="notification"></param>
/// <returns></returns>
public async Task Handle( TNotification notification )
{
using ( var perHandlerScope = _scope.BeginLifetimeScope(
LifeTimeScopeKeys.PerHandlerKey ) )
{
var decoratedHandler =
perHandlerScope.ResolveKeyed<IAsyncNotificationHandler<TNotification>>(
"IAsyncNotificationHandlerKey" );
await decoratedHandler.Handle( notification );
}
}
}
Currently I am using the following:
Stopwatch stopWatchB = new Stopwatch();
stopWatchB.Start();
_callIndex.Test = _callTable.Get(u => u.PartitionKey == _callIndex.PageMeta.User & u.RowKey == "A");
stopWatchB.Stop();
em1 = stopWatchB.ElapsedMilliseconds;
My code works great but looks so messy. Stopwatches starting and stopping :-( Is there any way that I could clean this up. Note that I can't change the .Get() method and the data returned to _callIndex.Test is a class called Test that has multiple fields.
Well, to start with you can use:
Stopwatch stopWatchB = Stopwatch.StartNew();
You could also take the ElapsedMilliseconds without stopping it first, if you wanted:
Stopwatch stopWatchB = Stopwatch.StartNew();
_callIndex.Test = _callTable.Get(
u => u.PartitionKey == _callIndex.PageMeta.User & u.RowKey == "A");
em1 = stopWatchB.ElapsedMilliseconds;
That's a bit simpler. Alternatively, you could create a helper method:
public static TimeSpan Time(Action action)
{
Stopwatch stopwatch = Stopwatch.StartNew();
action();
return stopwatch.Elapsed;
}
Then:
em1 = StopwatchHelper.Time(() => {
_callIndex.Test = _callTable.Get(
u => u.PartitionKey == _callIndex.PageMeta.User & u.RowKey == "A");
}).TotalMilliseconds;
I use this to do "benchmark"
for using it:
using(var b = new bench())
{
//stuff
em1 = b.ElapsedMilliseconds;
}
///
class bench : Stopwatch, IDisposable
{
private static bool enabled = true;
public static bool Enabled
{
get { return enabled; }
set { enabled = value; }
}
private string func;
/// <summary>
/// Initializes a new instance of the <see cref="bench"/> class.
/// </summary>
public bench()
{
begin("", false, false);
}
/// <summary>
/// Initializes a new instance of the <see cref="bench"/> class.
/// </summary>
/// <param name="showStack">if set to <c>true</c> [show stack].</param>
public bench(bool showStack)
{
begin("", showStack, false);
}
/// <summary>
/// Initializes a new instance of the <see cref="bench"/> class.
/// </summary>
/// <param name="showStack">if set to <c>true</c> [show stack].</param>
/// <param name="showStart">if set to <c>true</c> [show start].</param>
public bench(bool showStack, bool showStart)
{
begin("", showStack, showStart);
}
/// <summary>
/// Initializes a new instance of the <see cref="bench"/> class.
/// </summary>
/// <param name="func">The func.</param>
public bench(String func)
{
begin(func, false, false);
}
/// <summary>
/// Initializes a new instance of the <see cref="bench"/> class.
/// </summary>
/// <param name="func">The func.</param>
/// <param name="showStack">if set to <c>true</c> [show stack].</param>
public bench(String func, bool showStack)
{
begin(func, showStack, false);
}
/// <summary>
/// Initializes a new instance of the <see cref="bench"/> class.
/// </summary>
/// <param name="func">The func.</param>
/// <param name="showStack">if set to <c>true</c> [show stack].</param>
/// <param name="showStart">if set to <c>true</c> [show start].</param>
public bench(String func, bool showStack, bool showStart)
{
begin(func, showStack, showStart);
}
/// <summary>
/// Begins the specified func.
/// </summary>
/// <param name="func">The func.</param>
/// <param name="showStack">if set to <c>true</c> [show stack].</param>
/// <param name="showStart">if set to <c>true</c> [show start].</param>
private void begin(String func, bool showStack, bool showStart)
{
if (bench.Enabled)
{
this.func = func;
if (showStack || showStart)
Debug.WriteLine("Start " + func);
if (showStack)
Debug.WriteLine("Stack: " + Environment.StackTrace);
this.Start();
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
if (bench.Enabled || this.IsRunning)
{
this.Stop();
if (bench.Enabled)
{
Debug.WriteLine("Stop " + func + " " + Elapsed.TotalSeconds.ToString("0.#######") + " seconds");
}
}
}
}
Create a class that implements IDisposable, and starts a stopwatch on creation, stopping it when disposed.
You can create a class that manages such items, as in my code here:
https://stackoverflow.com/questions/6410569/speeding-up-performance-monitoring-code
It does quite a bit more than you ask (handling timing 'child' code and rendering timing values), however you can hopefully get the basic idea.
EDIT: For a simple example, see #Fredou's answer.
You can write the class which starts Stopwatch in the constructor and stops in the Dispose() (obviously you have to implement IDisposable).
using (var profiler = new PerformanceProfiler(out elapsedMilliseconds)
{
// profiled action code ...
}
Debug.WriteLine(elapsedMilliseconds.ToString(CultureInfo.CurrentCulture));