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>() { };
}
}
Related
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 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());
}
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 wrote an asynchronous class which can run the function asynchronously, well, the fact is the class is very ugly, see below:
using System;
using System.Windows.Forms;
namespace AsyncLibery
{
public class AsyncLib
{
public AsyncLib() { }
public AsyncLib(Object myObject)
{
this.MyObject = myObject;
}
public Object MyObject { get; set; }
/// <summary>
/// No Parameter,WithOut ReturnValue
/// </summary>
/// <param name="actionFunction">the function needed to be delegated</param>
public void Async(Action actionFunction)
{
Form form = (MyObject as Form);
form.Invoke((Action)(() => actionFunction()));
}
/// <summary>
/// No parameter, With returnValue
/// </summary>
/// <param name="funcFunction">the function needed to be delegated</param>
/// <returns>return object type</returns>
public object AsyncWithReturnValue(Func<object> funcFunction)
{
object returnValue = null;
Form form = (MyObject as Form);
form.Invoke(new Func<object>(delegate()
{
returnValue = funcFunction();
return returnValue;
}));
return returnValue;
}
/// <summary>
/// One Parameter, With ReturnValue
/// </summary>
/// <param name="funcFunction">the function needed to be delegated</param>
/// <param name="inputValue">the input parameter</param>
/// <returns></returns>
public object AsyncWithReturnValue(Func<object, object> funcFunction, object inputValue)
{
object returnValue = null;
Form form = (MyObject as Form);
form.Invoke(new Func<object,object>(delegate(object _object)
{
returnValue = funcFunction(_object);
return returnValue;
}),inputValue);
return returnValue;
}
/// <summary>
/// Two Parameters , With ReturnValue
/// </summary>
/// <param name="funcFunction">the function needed to be delegated</param>
/// <param name="inputValue1">the first input parameter</param>
/// <param name="inputValue2">this second input parameter</param>
/// <returns></returns>
public object AsyncWithReturnValue(Func<object, object, object> funcFunction, object inputValue1, object inputValue2)
{
object returnValue = null;
Form form = (MyObject as Form);
form.Invoke(new Func<object, object,object>(delegate(object _object1,object _object2)
{
returnValue = funcFunction(_object1,_object2);
return returnValue;
}), inputValue1,inputValue2);
return returnValue;
}
/// <summary>
/// Three Parameters, With ReturnValue
/// </summary>
/// <param name="funcFunction">the function needed to be delegated</param>
/// <param name="inputValue1">the first input parameter</param>
/// <param name="inputValue2">the second input parameter</param>
/// <param name="inputValue3">the third input parameter</param>
/// <returns></returns>
public object AsyncWithReturnValue(Func<object, object, object, object> funcFunction, object inputValue1, object inputValue2, object inputValue3)
{
object returnValue = null;
Form form = (MyObject as Form);
form.Invoke(new Func<object, object, object,object>(delegate(object _object1, object _object2,object _object3)
{
returnValue = funcFunction(_object1, _object2,_object3);
return returnValue;
}), inputValue1, inputValue2,inputValue3);
return returnValue;
}
/// <summary>
/// One Parameter,WithOut ReturnValue
/// </summary>
/// <param name="actionFunction">the function needed to be delegated</param>
/// <param name="inputValue">the input prameter</param>
public void AsyncWithOutReturnValue(Action<object> actionFunction, object inputValue)
{
Form form = (MyObject as Form);
form.Invoke(new Action<object>(delegate(object _object)
{
actionFunction(_object);
}),inputValue);
}
/// <summary>
/// Two Parameters,WithOut ReturnValue
/// </summary>
/// <param name="actionFunction">the function needed to be delegated</param>
/// <param name="inputValue1">the first input parameter</param>
/// <param name="inputValue2">the second input parameter</param>
public void AsyncWithOutReturnValue(Action<object,object> actionFunction, object inputValue1,object inputValue2)
{
Form form = (MyObject as Form);
form.Invoke(new Action<object,object>(delegate(object _object1,object _object2)
{
actionFunction(_object1,_object2);
}), inputValue1,inputValue2);
}
/// <summary>
/// Three Parameters, WithOut ReturnValue
/// </summary>
/// <param name="actionFunction">the function needed to be delegated</param>
/// <param name="inputValue1">the first input parameter</param>
/// <param name="inputValue2">the second input paramter</param>
/// <param name="inputValue3">the third input parameter</param>
public void AsyncWithOutReturnValue(Action<object, object,object> actionFunction, object inputValue1, object inputValue2,object inputValue3)
{
Form form = (MyObject as Form);
form.Invoke(new Action<object, object,object>(delegate(object _object1, object _object2,object _object3)
{
actionFunction(_object1, _object2,_object3);
}), inputValue1, inputValue2,inputValue3);
}
}
}
now I used the class like below:
using System;
using System.Windows.Forms;
namespace AsyncLibAPP
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
asyncLib = new AsyncLibery.AsyncLib(this);
}
AsyncLibery.AsyncLib asyncLib;
private void Form1_Load(object sender, EventArgs e)
{
}
private void test()
{
button1.Text = "test";
}
private string test1()
{
label1.Text = "test";
return "test";
}
private string test2(object value)
{
label1.Text = value.ToString();
return "test,test";
}
private void test3(object s)
{
label1.Text = s.ToString();
}
private void test4(object s1, object s2, object s3)
{
label1.Text = s1.ToString() + s2.ToString() + s3.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
//asyncLib.RunAsyncCrossThreads(test);
//string value = asyncLib.AsyncWithNoParamOneReturnValue(test1).ToString();
//string value = asyncLib.Async(test2,"aaaa").ToString();
// MessageBox.Show(value);
//asyncLib.AsyncWithOutReturnValue(test3,"sssss");
asyncLib.AsyncWithOutReturnValue(test4,"aaaaaa","bbbbbbbb","cccccccc");
}
}
}
It runs ok, but seems so ugly.
I planned to use T instead of Object type, but I don't know how to do this.
Can anyone optimize it? thx very much.
One aspect about this code that is indeed very ugly is the word "Async". None of these methods are asynchronous, they are all synchronous calls that don't return until the invoked method has finished running.
But the biggest problem is that it just isn't necessary. You got lambdas at your disposal, you only ever need one method. A lambda can capture a variable. Your test code is best written like this:
private void button1_Click(object sender, EventArgs e) {
string value = "aaaaaa";
this.Invoke(new Action(() => test4(value, "bbbbbbbb", "cccccccc")));
}
With a fake value variable to avoid making it too trivial. And keep in mind that you almost always want to use BeginInvoke(), making a worker thread block on the UI thread is not productive. Except when you need a return value, then Invoke() is required. Which is in itself almost always wrong, workers should be started with the arguments they need. Whatever you get from a UI component by using Invoke() later is going to be pretty random since the worker is not in any way synchronized with the user's input.
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;
}