I am working on a proof of concept for using Unity and I am having issues with my interceptor being called. I am using policy injection.
so here is some code
setting up unity:
private void ApplyCrossCuttingConcerns(UnityContainer container)
{
container.AddNewExtension<Interception>();
container.RegisterType<IContact, Contact>(
new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<InterfaceInterceptor>());
container.Configure<Interception>()
.AddPolicy("extensionPolicy")
.AddMatchingRule<TypeMatchingRule>(new InjectionConstructor(typeof(Contact).ToString()))
.AddMatchingRule<MethodSignatureMatchingRule>(new InjectionConstructor("Save",new [] {""},true))
.AddCallHandler<ExtensionHandler>(new ContainerControlledLifetimeManager(), new InjectionConstructor());
}
my contact class that inherites from BussinessObject where the method in question lives
public class Contact : BussinessObject, IContact
{...}
public abstract class BussinessObject
{
#region Local Vars
protected readonly IRepository _repository;
protected bool isNew;
#endregion Local Vars
#region Properties
/// <summary>
/// Gets or sets a value indicating whether this instance is new.
/// </summary>
/// <value>
/// <see langword="true" /> if this instance is new; otherwise, <see langword="false" />.
/// </value>
internal bool IsNew { get { return (isNew); } set { isNew = value; } }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="BussinessObject"/> class.
/// </summary>
/// <param name="repository">The repository.</param>
public BussinessObject(IRepository repository)
{
if (repository.IsEmpty())
{
throw new Exception("The repository is a maditory parameter for a bussiness object");
}
_repository = repository;
}
#endregion Constructors
#region Methods
#region public
/// <summary>
/// Saves this instance.
/// </summary>
public virtual void Save()
{
Validate();
SetIdenity();
if (isNew)
{
Insert();
}
else
{
Update();
}
isNew = false;
}
/// <summary>
/// Permantlies the remove from system.
/// </summary>
/// <param name="ID">The identifier.</param>
public abstract void PermantlyRemoveFromSystem(Guid id);
#endregion public
#region Internal
/// <summary>
/// Sets the idenity.
/// </summary>
internal abstract void SetIdenity();
#endregion Internal
#region protected
/// <summary>
/// Commons the initialize.
/// </summary>
protected virtual void CommonInit()
{
isNew = false;
}
/// <summary>
/// Inserts this instance.
/// </summary>
protected abstract void Insert();
/// <summary>
/// Updates this instance.
/// </summary>
protected abstract void Update();
/// <summary>
/// Validates this instance.
/// </summary>
protected abstract void Validate();
#endregion protected
#endregion
}
Now the IContact
public interface IContact : DTO.IContact
{
void Save();
void Delete();
#region Phone Number Manipulation
bool SetDefaultNumber(PhoneNumber phNum);
PhoneNumber GetDefaultNumber();
bool HasDefaultNumber();
PhoneNumber[] GetPhoneNumbers();
PhoneNumber[] GetPhoneNumbers(bool includeDeleted);
void AddPhoneNumber(PhoneNumber phToAdd);
bool RemovePhoneNumber(PhoneNumber phToRemove);
#endregion
#region Email Address Manipulation
bool SetDefaultEMailAddress(EmailAddress emAdd);
bool HasDefaultEmailAddress();
EmailAddress[] GetAllEmailAddresses();
EmailAddress[] GetAllEmailAddresses(bool includeDeleted);
EmailAddress AddEmailAddress(string addressToAdd);
EmailAddress GetDefaultEMailAddress();
#endregion
#region Snailmail Address Manipulation
bool SetDefaultAddress(SnailMailAddress ad);
SnailMailAddress GetDefaultAddress();
bool HasDefaultAddress();
SnailMailAddress[] GetAllAddresses();
SnailMailAddress[] GetAllAddresses(bool includeDeleted);
void AddAddress(SnailMailAddress adToAdd);
bool RemoveAddress(SnailMailAddress adToRemove);
#endregion
}
and finally the extensionHandler
public class ExtensionHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
//going to do our work before we pass on to the next item in the pipeline
SomeFunctionality handlerFunctionality = new SomeFunctionality();
handlerFunctionality.PreformWork();
//pass on to the next item in the pipeline
var result = getNext().Invoke(input, getNext);
//we can put post processing logic in here
return result;
}
I setup a test to resolve the contact object and then set so data on it and called the save method. I have a break point at the top of the invoke method in the ExtensionHandler but I never get there. I think the issue with the way I configuring the MethodSignatureMatchingRule but I have not yet to find documentation on the net showing an example of interception being configured to a method with no parameters.
Any help would be appreaiated
so after some more experimentation I found the answer
This issue was in the matching rules
both rules where incorrect the correct code is as follows:
private void ApplyCrossCuttingConcerns(UnityContainer container)
{
container.AddNewExtension<Interception>();
container.RegisterType<IContact, Contact>(
new InterceptionBehavior<PolicyInjectionBehavior>(),
new Interceptor<InterfaceInterceptor>());
container.Configure<Interception>()
.AddPolicy("extensionPolicy")
.AddMatchingRule<TypeMatchingRule>(new InjectionConstructor(new InjectionParameter(typeof(IContact))))
.AddMatchingRule<MemberNameMatchingRule>(new InjectionConstructor(new InjectionParameter("Save")))
.AddCallHandler<ExtensionHandler>(new ContainerControlledLifetimeManager(), new InjectionConstructor());
}
Related
In real time, i want to register a variable to my other scripts at start and want it to be controlled at realtime by other script.
public float leftTime;
MyManager.RegisterVariable(leftTime);
thats all, now i want my manager to control this variable by it self in update.
How can i make this?
Keep setter and getter functions in MyManager then take them and save them in RegisterVariable:
// in MyManager
static Action<float> varSetter;
static Func<float> varGetter;
static void RegisterVariable(Action<float> setter, Func<float> getter)
{
varSetter = setter;
varGetter = getter;
}
static void SomeFunction()
{
float oldFloatValue = varGetter();
float newFloatValue = oldFloatValue + 5f;
varSetter(newFloatValue);
}
Then, when you call RegisterVariable, pass getter and setter. I recommend using anonymous functions if you don't plan on calling this frequently.
// in other script
float foobar = 5f;
void SomeOtherFunction()
{
MyManager.RegisterVariable((f) => {foobar = f;}, ()=> {return foobar;});
}
Now you need to return the ptr to the space or the Dictionary which contains the vars!
public interface IRunningStatistic
{
/// <summary>
/// Collects a value
/// </summary>
/// <param name="value"></param>
void Collect(decimal value);
/// <summary>
/// The <see cref="IStatisticalFunction"/>'s which are run in the order inserted
/// </summary>
IList<IStatisticalFunction> Functions { get; }
}
/// <summary>
/// Represents a function
/// </summary>
public interface IStatisticalFunction
{
/// <summary>
/// The <see cref="IRunningStatistic"/> to which this instance belongs
/// </summary>
IRunningStatistic Statistic { get; }
/// <summary>
/// The name of the function
/// </summary>
string Name { get; }
/// <summary>
/// A function accepting input
/// </summary>
/// <param name="value"></param>
void Collect(decimal value);
/// <summary>
/// Gets all variables by name with their values
/// </summary>
/// <returns></returns>
Dictionary<string, decimal> GetState();
//SetState / Load
//Could use an array or dictionary
}
class InternalFunctionRepresentation : IStatisticalFunction
{
public IRunningStatistic Statistic { get; private set; }
public string Name { get; private set;}
private readonly Action<decimal> Function;
public InternalFunctionRepresentation(IRunningStatistic statistic, string name, Action<decimal> function)
{
(Statistic, Name, Function) = (statistic, name, function);
}
public void Collect(decimal value)
{
Function(value);
}
public Dictionary<string, decimal> GetState()
{
//if i was a byte[] this would be easyer
return new Dictionary<string, decimal>() { };
}
}
Hey i'm new to literally everything, sorry if this was solved but i'm having trouble editing a script from Unity's Platformer 2D Game. There's an Error where Player can't die and the error NullReferenceException: Object reference not set to an instance of an object. But idk the solution.
NullReferenceException: Object reference not set to an instance of an object
Platformer.Gameplay.PlayerDeath.Execute () (at Assets/Scripts/Gameplay/PlayerDeath.cs:20)
Platformer.Core.Simulation+Event`1[T].ExecuteEvent () (at Assets/Scripts/Core/Simulation.Event.cs:57)
Platformer.Core.Simulation.Tick () (at Assets/Scripts/Core/Simulation.cs:114)
Platformer.Mechanics.GameController.Update () (at Assets/Scripts/Mechanics/GameController.cs:40)
This is my PlayerDeath
using System.Collections;
using System.Collections.Generic;
using Platformer.Core;
using Platformer.Model;
using UnityEngine;
namespace Platformer.Gameplay
{
/// <summary>
/// Fired when the player has died.
/// </summary>
/// <typeparam name="PlayerDeath"></typeparam>
public class PlayerDeath : Simulation.Event<PlayerDeath>
{
PlatformerModel model = Simulation.GetModel<PlatformerModel>();
public override void Execute()
{
var player = model.player;
if (player.health.IsAlive)
{
player.health.Die();
model.virtualCamera.m_Follow = null;
model.virtualCamera.m_LookAt = null;
// player.collider.enabled = false;
player.controlEnabled = false;
if (player.audioSource && player.ouchAudio)
player.audioSource.PlayOneShot(player.ouchAudio);
player.animator.SetTrigger("hurt");
player.animator.SetBool("dead", true);
Simulation.Schedule<PlayerSpawn>(2);
}
}
}
}
This is my Simulation.Event
using System.Collections.Generic;
namespace Platformer.Core
{
public static partial class Simulation
{
/// <summary>
/// An event is something that happens at a point in time in a simulation.
/// The Precondition method is used to check if the event should be executed,
/// as conditions may have changed in the simulation since the event was
/// originally scheduled.
/// </summary>
/// <typeparam name="Event"></typeparam>
public abstract class Event : System.IComparable<Event>
{
internal float tick;
public int CompareTo(Event other)
{
return tick.CompareTo(other.tick);
}
public abstract void Execute();
public virtual bool Precondition() => true;
internal virtual void ExecuteEvent()
{
if (Precondition())
Execute();
}
/// <summary>
/// This method is generally used to set references to null when required.
/// It is automatically called by the Simulation when an event has completed.
/// </summary>
internal virtual void Cleanup()
{
}
}
/// <summary>
/// Event<T> adds the ability to hook into the OnExecute callback
/// whenever the event is executed. Use this class to allow functionality
/// to be plugged into your application with minimal or zero configuration.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class Event<T> : Event where T : Event<T>
{
public static System.Action<T> OnExecute;
internal override void ExecuteEvent()
{
if (Precondition())
{
Execute();
OnExecute?.Invoke((T)this);
}
}
}
}
}
This is my Simulation
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Platformer.Core
{
/// <summary>
/// The Simulation class implements the discrete event simulator pattern.
/// Events are pooled, with a default capacity of 4 instances.
/// </summary>
public static partial class Simulation
{
static HeapQueue<Event> eventQueue = new HeapQueue<Event>();
static Dictionary<System.Type, Stack<Event>> eventPools = new Dictionary<System.Type, Stack<Event>>();
/// <summary>
/// Create a new event of type T and return it, but do not schedule it.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
static public T New<T>() where T : Event, new()
{
Stack<Event> pool;
if (!eventPools.TryGetValue(typeof(T), out pool))
{
pool = new Stack<Event>(4);
pool.Push(new T());
eventPools[typeof(T)] = pool;
}
if (pool.Count > 0)
return (T)pool.Pop();
else
return new T();
}
/// <summary>
/// Clear all pending events and reset the tick to 0.
/// </summary>
public static void Clear()
{
eventQueue.Clear();
}
/// <summary>
/// Schedule an event for a future tick, and return it.
/// </summary>
/// <returns>The event.</returns>
/// <param name="tick">Tick.</param>
/// <typeparam name="T">The event type parameter.</typeparam>
static public T Schedule<T>(float tick = 0) where T : Event, new()
{
var ev = New<T>();
ev.tick = Time.time + tick;
eventQueue.Push(ev);
return ev;
}
/// <summary>
/// Reschedule an existing event for a future tick, and return it.
/// </summary>
/// <returns>The event.</returns>
/// <param name="tick">Tick.</param>
/// <typeparam name="T">The event type parameter.</typeparam>
static public T Reschedule<T>(T ev, float tick) where T : Event, new()
{
ev.tick = Time.time + tick;
eventQueue.Push(ev);
return ev;
}
/// <summary>
/// Return the simulation model instance for a class.
/// </summary>
/// <typeparam name="T"></typeparam>
static public T GetModel<T>() where T : class, new()
{
return InstanceRegister<T>.instance;
}
/// <summary>
/// Set a simulation model instance for a class.
/// </summary>
/// <typeparam name="T"></typeparam>
static public void SetModel<T>(T instance) where T : class, new()
{
InstanceRegister<T>.instance = instance;
}
/// <summary>
/// Destroy the simulation model instance for a class.
/// </summary>
/// <typeparam name="T"></typeparam>
static public void DestroyModel<T>() where T : class, new()
{
InstanceRegister<T>.instance = null;
}
/// <summary>
/// Tick the simulation. Returns the count of remaining events.
/// If remaining events is zero, the simulation is finished unless events are
/// injected from an external system via a Schedule() call.
/// </summary>
/// <returns></returns>
static public int Tick()
{
var time = Time.time;
var executedEventCount = 0;
while (eventQueue.Count > 0 && eventQueue.Peek().tick <= time)
{
var ev = eventQueue.Pop();
var tick = ev.tick;
ev.ExecuteEvent();
if (ev.tick > tick)
{
//event was rescheduled, so do not return it to the pool.
}
else
{
// Debug.Log($"<color=green>{ev.tick} {ev.GetType().Name}</color>");
ev.Cleanup();
try
{
eventPools[ev.GetType()].Push(ev);
}
catch (KeyNotFoundException)
{
//This really should never happen inside a production build.
Debug.LogError($"No Pool for: {ev.GetType()}");
}
}
executedEventCount++;
}
return eventQueue.Count;
}
}
}
and this is my GameController
using Platformer.Core;
using Platformer.Model;
using UnityEngine;
namespace Platformer.Mechanics
{
/// <summary>
/// This class exposes the the game model in the inspector, and ticks the
/// simulation.
/// </summary>
public class GameController : MonoBehaviour
{
public static GameController Instance { get; private set; }
//This model field is public and can be therefore be modified in the
//inspector.
//The reference actually comes from the InstanceRegister, and is shared
//through the simulation and events. Unity will deserialize over this
//shared reference when the scene loads, allowing the model to be
//conveniently configured inside the inspector.
public PlatformerModel model = Simulation.GetModel<PlatformerModel>();
void Start()
{
Screen.SetResolution(1280, 720, true);
}
void OnEnable()
{
Instance = this;
}
void OnDisable()
{
if (Instance == this) Instance = null;
}
void Update()
{
if (Instance == this) Simulation.Tick();
}
}
}
I was dealing with the same issue. The problem generally begins when we write a custom player instead of using the default.
What you need to do, at least for the 2D Platformer microgame, is open up the GameObject called "GameController" (should be right up at the top) and drag your player* onto the Player field under the GameController component.
*Specifically, the GameObject that has your PlayerController component.
(I really like that Unity is diving into a full event system like Qt, but this Simulation class seems very convoluted and graceless to me. We'll see what I think as I progress with it; but I doubt it's that much more efficient than cached GameObject.Find calls.)
That should solve your problem!
I'm using a specialization of Stephen Cleary's AsyncLazy implementation, from his blog.
/// <summary>
/// Provides support for asynchronous lazy initialization.
/// This type is fully thread-safe.
/// </summary>
/// <typeparam name="T">
/// The type of object that is being asynchronously initialized.
/// </typeparam>
public sealed class AsyncLazy<T>
{
/// <summary>
/// The underlying lazy task.
/// </summary>
private readonly Lazy<Task<T>> instance;
/// <summary>
/// Initializes a new instance of the
/// <see cref="AsyncLazy<T>"/> class.
/// </summary>
/// <param name="factory">
/// The delegate that is invoked on a background thread to produce
/// the value when it is needed.
/// </param>
/// <param name="start">
/// If <c>true</c> commence initialization immediately.
/// </param>
public AsyncLazy(Func<T> factory, bool start = false)
{
this.instance = new Lazy<Task<T>>(() => Task.Run(factory));
if (start)
{
this.Start();
}
}
/// <summary>
/// Initializes a new instance of the
/// <see cref="AsyncLazy<T>"/> class.
/// </summary>
/// <param name="factory">
/// The asynchronous delegate that is invoked on a background
/// thread to produce the value when it is needed.
/// </param>
/// <param name="start">
/// If <c>true</c> commence initialization immediately.
/// </param>
public AsyncLazy(Func<Task<T>> factory, bool start = false)
{
this.instance = new Lazy<Task<T>>(() => Task.Run(factory));
if (start)
{
this.Start();
}
}
/// <summary>
/// Asynchronous infrastructure support.
/// This method permits instances of
/// <see cref="AsyncLazy<T>"/> to be await'ed.
/// </summary>
public TaskAwaiter<T> GetAwaiter()
{
return this.instance.Value.GetAwaiter();
}
/// <summary>
/// Starts the asynchronous initialization,
/// if it has not already started.
/// </summary>
public void Start()
{
var unused = this.instance.Value;
}
}
This is great code and I really appreciate how easy it is to use. i.e.
class SomeClass
{
private readonly AsyncLazy<Thing> theThing = new AsyncLazy<Thing>(
() => new Thing());
void SomeMethod()
{
var thing = await theThing;
// ...
}
}
Now my question,
Suppose that SomeClass inherits from a class that implements IDisposable and that Thing implements IDisposable. We'd have skeleton implementation like this,
class SomeClass : SomeDisposableBase
{
private readonly AsyncLazy<Thing> theThing = new AsyncLazy<Thing>(
() => new Thing());
protected override void Dispose(bool disposing)
{
if (disposing)
{
// What do I do with theThing?
}
base.Dispose(disposing);
}
}
So, what do I do with theThing in the Dispose override? Should I extend AsyncLazy<T> to have a new property?
// ...
public bool IsStarted
{
get
{
return this.instance.IsValueCreated;
}
}
// ...
Should I change AsyncLazy<T> to implement IDisposable?
Have I misunderstood and I don't need to worry?
Should I do something else?
Stephen Toub's version of this class inherits from Lazy<Task<T>>, so you get the IsValueCreated property automatically.
Alternatively, you could expose the IsValueCreated property from the private field:
public sealed class AsyncLazy<T>
{
private readonly Lazy<Task<T>> instance;
...
public bool IsValueCreated
{
get { return instance.IsValueCreated; }
}
}
For consistency with the built-in Lazy<T> type, I'd avoid renaming the property to IsStarted.
You can use a bool inside the AsyncLazy<T> initialization to know if theThing has been initialized
class SomeClass : SomeDisposableBase
{
public SomeClass()
{
theThing = new AsyncLazy<Thing>(() =>
{
_isInitialized = true;
return new Thing();
}
}
private bool _isInitialized;
private readonly AsyncLazy<Thing> theThing;
protected override void Dispose(bool disposing)
{
if (disposing && _isInitialized)
{
// Dispose Thing
}
base.Dispose(disposing);
}
}
Although, if this pattern occurs in your code more than once, then i would definitely extend AsyncLazy
I have a class to hold session like this
public class SessionService : ISession
{
public HttpContext Context { get; set; }
public SessionService(HttpContext context)
{
this.Context = context;
}
}
I want to be able to inject the session object in various places in my MVC3 app.
I have this interface
interface ISession
{
HttpContext Context { get; set; }
}
I am using ninject to bind the session class to the interface like this
private void RegisterDependencyResolver()
{
var kernel = new StandardKernel();
kernel.Bind<ISession>().To<SessionService>();
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
My problem is how to pass the Httpcontext parameter into the SessionService constructor.
Any pointers most appreciated.
Thanks
Wherever you are setting up your dependencies:
kernel.Bind<HttpContext>().ToMethod(c => HttpContext.Current);
I have a bootstrapper class that does this with a RegisterServices method:
public static class NinjectMVC3
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<HttpContext>().ToMethod(c => HttpContext.Current);
}
}
I'm currently using Unity IoC Container and here is my AppConfig class. As you can see the Initialize method should be called only once and I have used double lock checking to ensure that.
What would be the best way to implement achieve this if my approach is not the best way?
public interface IAppConfig
{
/// <summary>
/// Gets the admin username.
/// </summary>
/// <value>The admin username.</value>
string AdminUsername { get; }
/// <summary>
/// Gets the admin password.
/// </summary>
/// <value>The admin password.</value>
string AdminPassword { get; }
/// <summary>
/// Initializes this instance.
/// </summary>
void Initialize();
}
/// <summary>
/// A singleton App config which helps reading from web.config
/// its lifetime is controlled by Unity.
/// </summary>
public class AppConfig : IAppConfig
{
#region Fields
/// <summary>
/// the injectable config manager
/// </summary>
private readonly IConfigManager _configManager;
private readonly ILogger _logger;
private static readonly object LockObject = new object();
private static bool _initialized = false;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="AppConfig"/> class.
/// </summary>
public AppConfig(IConfigManager configManager, ILogger logger)
{
this._configManager = configManager;
this._logger = logger;
}
#endregion
#region Properties
/// <summary>
/// Gets the admin username.
/// </summary>
/// <value>The admin username.</value>
public string AdminUsername { get; private set; }
/// <summary>
/// Gets the admin password.
/// </summary>
/// <value>The admin password.</value>
public string AdminPassword { get; private set; }
#endregion
#region Methods
public void Initialize()
{
if (_initialized)
{
throw new ApplicationException("Initialize method should be called only once");
}
lock(LockObject)
{
if (_initialized) return;
var adminUserNameSetting = _configManager.AppSettings[ConfigKeys.AdminUsername];
if (adminUserNameSetting == null)
{
throw new ApplicationException("AdminUsername key not found");
}
this.AdminUsername = adminUserNameSetting.Value;
if (String.IsNullOrWhiteSpace(this.AdminUsername))
{
_logger.LogError("AdminUsername not found");
}
// log
var adminPasswordSetting = _configManager.AppSettings[ConfigKeys.AdminPassword];
if (adminPasswordSetting == null)
{
throw new ApplicationException("AdminPassword key not found");
}
this.AdminPassword = adminPasswordSetting.Value;
if (String.IsNullOrWhiteSpace(this.AdminPassword))
{
_logger.LogError("AdminPassword not found");
}
_initialized = true;
}
}
#endregion
}
In the Unity, I'm using the below code:
// IAppConfig
container.RegisterType<IAppConfig, AppConfig>(new ContainerControlledLifetimeManager(),
new InjectionConstructor(configManager,
logger));
var appConfig = container.Resolve<IAppConfig>();
appConfig.Initialize();
I think an Initalize() method tastes more like an implementation issue. And that means that maybe it shouldn't be in the interface at all.
Initializing an instance is best left to the constructor.
If you really need a delayed Initialize then you solution with a bool and a lock seems OK.
Judging by what you are doing in the Initialize method, I think what you need to look into is registering that class as a singleton and persisting the container. You can see an example of doing this here:
http://gunnarpeipman.com/2008/04/unity-and-singletons/
Okay so you're relying on Unity to ensure that you class is a singleton. Although the code pattern for C# is quite easy. See here. Then call initialisation code in the constructor.
In any case I would declare your initialization flag volatile as the code stands atmo.
I prefer to have a static class instance variable that checks to see if it has been initialized in the get accessor. Access the class through the instance property and you will control how many times the class is initialized. This is pretty much the default C# singleton pattern:
public static class MySingleton
{
private static Mutex instanceLock = new Mutex();
private static MySingleton instance;
public static MySingleton Instance
{
get
{
instanceLock.WaitOne();
if(instance == null)
{
instance = new MySingleton();
}
instanceLock.ReleaseMutex();
return instance;
}
}
private MySingleton()
{
Initialize();
}
private void Initialize()
{
// Initialize
}
}
public class MyOtherClass
{
private MySingleton singleton = MySingleton.Instance;
}