Consider the sample code below consisting of a Class Library design and an executable Program using the library.
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
m_StageApp = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
// Question: How to add actor to stage?
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
Question
Stage and Actor have circular dependency and seems bad to me.
For example, how should we add actors to stage?
If I let user to create new Actor() themselves,
then they must keep on supplying the Stage.
If I give Actor() an internal constructor and make Stage a factory,
then I lose some of the flexibility for users to do making inherited Actors.
If I make Stage a singleton, then I can only have one set of SharedSetting.
In case the user wants more than one Stage in his AppExe, then it cannot be done.
Is there anyway to redesign the architecture so as to avoid the problems above?
If your functionality is not limited by sharing the StageApp settings between actors, but also will be some other logic. For example when you need to know parent StageApp from Actor and vice versa. I preffer to implement it in this way:
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public int TotalActorsCount
{
get
{
return m_actors.Count;
}
}
public void AddActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (m_actors.Contains(actor))
return; // or throw an exception
m_actors.Add(actor);
if (actor.Stage != this)
{
actor.Stage = this;
}
}
// we are hiding this method, to avoid because we can change Stage only to another non null value
// so calling this method directly is not allowed
internal void RemoveActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (!m_actors.Contains(actor))
return; // or throuw exception
m_actors.Remove(actor);
}
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
public StageApp Stage
{
get
{
return m_StageApp;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (m_StageApp != value)
{
if (m_StageApp != null) // not a call from ctor
{
m_StageApp.RemoveActor(this);
}
m_StageApp = value;
m_StageApp.AddActor(this);
}
}
}
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
Stage = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
StageApp anotherApp = new StageApp();
anotherApp.SharedSetting = 6;
// actor is added to the stage automatically after instantiation
Actor a1 = new Actor(app);
Actor a2 = new Actor(app);
Actor a3 = new Actor(anotherApp);
Console.WriteLine("Actors in anotherApp before moving actor:");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by calling method from StageApp class
anotherApp.AddActor(a1);
Console.WriteLine("Actors in anotherApp after calling method (should be 2):");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by setting Stage through property
a2.Stage = anotherApp;
Console.WriteLine("Actors in anotherApp after setting property of Actor instance (should be 3):");
Console.WriteLine(anotherApp.TotalActorsCount);
Console.WriteLine("Actors count in app (should be empty):");
Console.WriteLine(app.TotalActorsCount);
}
}
}
It allows to you to manipulate with object relationships transparently, but requires a little bit mor code to implement.
How about adding a new class "ActorRole" that defines the behaviour of the actor in each Stage. It lets you decouple Actor and Stage from each other, so you can instantiate both independently (through a factory for example) and then combine them creating ActorRole objects that configure your stages. This combinations can be made using a Builder pattern if it is needed.
If you need to dynamically change your actor behaviour, you can use a Strategy pattern based on the ActorRole class, so depending on the Stage, you can assign to the actor different concrete implementations of its behaviour.
I would solve it by using Func instead of passing in the Stage to the Actor. Like this:
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.CreateActor();
app.SharedSetting = 5;
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
namespace AppLib
{
class StageApp
{
public int SharedSetting { get; set; }
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public void CreateActor()
{
m_actors.Add(new Actor(Executed));
}
private int Executed(int arg)
{
return SharedSetting * arg;
}
}
class Actor
{
private int m_Property;
private Func<int, int> m_executed;
public Actor(Func<int, int> executed)
{
m_executed = executed;
m_Property = new Random().Next();
}
public int Execute()
{
return m_executed(m_Property);
}
}
}
I totally agree with you that circular references is not fun :).
You could also solve this using events, but I like passing functions like callback.
Related
I have this code.
<ParentComponent>
<ChildComponet>
#renderFragment
</ChildComponent>
<ChildComponetn>
<GridComponent Data="#dataList"/>
</ChildComponent>
</ParentComponent>
where #renderFragment is dynamically render componet and Grid componet is list of some data with actions like "add new", "edit record", "delete".
If we click "add new", form for add new record is opened dynamically in #renderFragment and we want to refresh grid data after submit form but we don't know how to share some data between two child components. Same is about edit form, when some record is edited, we need to refresh grid component to show edited data.
If need more code and data about it please comment.
You may define a class service that implements the State pattern and the Notifier pattern to handle the state of your objects, pass state to objects, and notify subscriber objects of changes.
Here's a simplified example of such service, which enables a parent component to communicate with his children.
NotifierService.cs
public class NotifierService
{
private readonly List<string> values = new List<string>();
public IReadOnlyList<string> ValuesList => values;
public NotifierService()
{
}
public async Task AddTolist(string value)
{
values.Add(value);
await Notify?.Invoke();
}
public event Func<Task> Notify;
}
Child1.razor
#inject NotifierService Notifier
#implements IDisposable
<div>User puts in something</div>
<input type="text" #bind="#value" />
<button #onclick="#AddValue">Add value</button>
#foreach (var value in Notifier.ValuesList)
{
<p>#value</p>
}
#code {
private string value { get; set; }
public async Task AddValue()
{
await Notifier.AddTolist(value);
}
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
Child2.razor
#inject NotifierService Notifier
<div>Displays Value from service and lets user put in new value</div>
<input type="text" #bind="#value" />
<button #onclick="#AddValue">Set Value</button>
#code {
private string value { get; set; }
public async Task AddValue()
{
await Notifier.AddTolist(value);
}
}
Usage
#page "/"
<p>
<Child1></Child1>
</p>
<p></p>
<p>
<Child2></Child2>
</p>
Startup.ConfigureServices
services.AddScoped<NotifierService>();
Hope this helps...
There are a few ways to do it, I just learned a really cool way using a Singleton class.
I have this component I use to send a message to other users in my chat called SubscriptionService, but you can use any class.
Add this inject to both of your components:
#inject Services.SubscriberService SubscriberService
#region using statements
using DataJuggler.UltimateHelper.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
#endregion
namespace BlazorChat.Services
{
#region class SubscriberService
/// <summary>
/// This class is used to subscribe to services, so other windows get a notification a new message
/// came in.
/// </summary>
public class SubscriberService
{
#region Private Variables
private int count;
private Guid serverId;
private List<SubscriberCallback> subscribers;
#endregion
#region Constructor
/// <summary>
/// Create a new instance of a 'SubscriberService' object.
/// </summary>
public SubscriberService()
{
// Create a new Guid
this.ServerId = Guid.NewGuid();
Subscribers = new List<SubscriberCallback>();
}
#endregion
#region Methods
#region BroadcastMessage(SubscriberMessage message)
/// <summary>
/// This method Broadcasts a Message to everyone that ins't blocked.
/// Note To Self: Add Blocked Feature
/// </summary>
public void BroadcastMessage(SubscriberMessage message)
{
// if the value for HasSubscribers is true
if ((HasSubscribers) && (NullHelper.Exists(message)))
{
// Iterate the collection of SubscriberCallback objects
foreach (SubscriberCallback subscriber in Subscribers)
{
// if the Callback exists
if ((subscriber.HasCallback) && (subscriber.Id != message.FromId))
{
// to do: Add if not blocked
// send the message
subscriber.Callback(message);
}
}
}
}
#endregion
#region GetSubscriberNames()
/// <summary>
/// This method returns a list of Subscriber Names ()
/// </summary>
public List<string> GetSubscriberNames()
{
// initial value
List<string> subscriberNames = null;
// if the value for HasSubscribers is true
if (HasSubscribers)
{
// create the return value
subscriberNames = new List<string>();
// Get the SubscriberNamesl in alphabetical order
List<SubscriberCallback> sortedNames = Subscribers.OrderBy(x => x.Name).ToList();
// Iterate the collection of SubscriberService objects
foreach (SubscriberCallback subscriber in sortedNames)
{
// Add this name
subscriberNames.Add(subscriber.Name);
}
}
// return value
return subscriberNames;
}
#endregion
#region Subscribe(string subscriberName)
/// <summary>
/// method returns a message with their id
/// </summary>
public SubscriberMessage Subscribe(SubscriberCallback subscriber)
{
// initial value
SubscriberMessage message = null;
// If the subscriber object exists
if ((NullHelper.Exists(subscriber)) && (HasSubscribers))
{
// Add this item
Subscribers.Add(subscriber);
// return a test message for now
message = new SubscriberMessage();
// set the message return properties
message.FromName = "Subscriber Service";
message.FromId = ServerId;
message.ToName = subscriber.Name;
message.ToId = subscriber.Id;
message.Data = Subscribers.Count.ToString();
message.Text = "Subscribed";
}
// return value
return message;
}
#endregion
#region Unsubscribe(Guid id)
/// <summary>
/// This method Unsubscribe
/// </summary>
public void Unsubscribe(Guid id)
{
// if the value for HasSubscribers is true
if ((HasSubscribers) && (Subscribers.Count > 0))
{
// attempt to find this callback
SubscriberCallback callback = Subscribers.FirstOrDefault(x => x.Id == id);
// If the callback object exists
if (NullHelper.Exists(callback))
{
// Remove this item
Subscribers.Remove(callback);
// create a new message
SubscriberMessage message = new SubscriberMessage();
// set the message return properties
message.FromId = ServerId;
message.FromName = "Subscriber Service";
message.Text = callback.Name + " has left the conversation.";
message.ToId = Guid.Empty;
message.ToName = "Room";
// Broadcast the message to everyone
BroadcastMessage(message);
}
}
}
#endregion
#endregion
#region Properties
#region Count
/// <summary>
/// This property gets or sets the value for 'Count'.
/// </summary>
public int Count
{
get { return count; }
set { count = value; }
}
#endregion
#region HasSubscribers
/// <summary>
/// This property returns true if this object has a 'Subscribers'.
/// </summary>
public bool HasSubscribers
{
get
{
// initial value
bool hasSubscribers = (this.Subscribers != null);
// return value
return hasSubscribers;
}
}
#endregion
#region ServerId
/// <summary>
/// This property gets or sets the value for 'ServerId'.
/// </summary>
public Guid ServerId
{
get { return serverId; }
set { serverId = value; }
}
#endregion
#region Subscribers
/// <summary>
/// This property gets or sets the value for 'Subscribers'.
/// </summary>
public List<SubscriberCallback> Subscribers
{
get { return subscribers; }
set { subscribers = value; }
}
#endregion
#endregion
}
#endregion
}
For my chat application, I want it available to all instances, so in your configure services method of Startup.cs, add a Sington:
services.AddSingleton<SubscriberService>();
To make it only available to this browser instance:
services.AddScoped(SubscriberService);
Now from both components you can call a method or get to properties on your injected class:
SubscriptionService.GetSubscribers();
Or if you prefer interfaces, I wrote a blog post about that and I don't want to duplicate the text:
https://datajugglerblazor.blogspot.com/2020/01/how-to-use-interfaces-to-communicate.html
The inject way is pretty cool though, as your entire application can communicate with other user instances for chat.
I draw the following topology where each node is an object of class SensorNode, the blue links indicate the links between each node with its neighbors where the circles around the nodes represent the transmission range for each node.
The sink also is an object of class Sink.
I need to instantiate messaging and communication between them but I have no idea what mechanisms should I used to perform message passing between theses objects (sensor nodes) where each node has its unique ID, the sink has a fixed ID which is 1 in my code because I use only a single sink.
The following are the classes where I am still stuck to how to implement send receive, and forward in terms of making this communication applicable between these different objects...
Class "SensorNode"
namespace CRN_Topology
{
class SensorNode
{
public int snID;
public string snName;
public int snDepth;
public DateTime schedulingTime;
public double holdingTime;
public double energy;
public List<int> queue11 = new List<int>();
public List<DateTime> queue12 = new List<DateTime>();
public List<Packet> queue21 = new List<Packet>();
public List<DateTime> queue22 = new List<DateTime>();
public SensorNode(int id,string name,int depth, double energy)
{
this.snID = id;
this.snName = name;
this.snDepth = depth;
this.energy = energy;
}
public void insertHistoryQueue(int packetID, DateTime receivingTime)
{
queue11.Add(packetID);
queue12.Add(receivingTime);
}
public void insertPriorityQueue(Packet packet, DateTime schedulingTime)
{
queue21.Add(packet);
queue22.Add(schedulingTime);
}
public DateTime schedulingTimeCalculations(double holdingTime, DateTime systemTime)
{
schedulingTime = DateTime.FromOADate(holdingTime).Date + systemTime.TimeOfDay;
return schedulingTime;
}
public double holdingTimeCalculations(double alpha, double depth, double beta)
{
holdingTime = alpha * depth + beta;
return holdingTime;
}
public void receive(Packet packet)
{
}
public void forward(Packet packet, int neighborID)
{
}
public void remove()
{
}
public void sendDirect(int rxID, Packet packet)
{
}
}
}
Class "Sink"
namespace CRN_Topology
{
class Sink
{
public string name;
public int sinkID;
public int sinkX;
public int sinkY;
public List<Packet> queue1 = new List<Packet>();
public List<DateTime> queue2 = new List<DateTime>();
public Sink(string name, int Id , int xLocation, int yLocation)
{
this.name = name;
this.sinkID = Id;
this.sinkX = xLocation;
this.sinkY = yLocation;
}
public void insert(Packet packet, DateTime receivingTime)
{
queue1.Add(packet);
queue2.Add(receivingTime);
}
}
}
Any idea, I need your suggestions and your help as I do not have an idea how to pass information between these objects (sensor nodes) and between the sensor nodes and the sink. What is the library which is responsible for this application in C#?
You could use actual events. Yet, for this case IObservable and IObserver seems to provide a better pattern. Although while trying to implement this, I quickly moved away from that pattern.
Below is the solution I developed. What I present is an abstract class Node indended to serve as base for SensorNode and Sink as both can recieve connections.
Edit 1: Or you may make it into its own thing and use composition, you may implement the abstract method Recieve to raise a custom event.
Edit 2: Perhaps it is better to thing of the Recieve method as Send? I mean, in my code the intended implementation is to have it use _connections to broadcast or try to get the Packet to its destination, and do logging and whatever else. I don really know if that is what you indended for your Recieve method.
abstract class Node
{
/// <summary>
/// Set of all the ids.
/// </summary>
private static readonly Dictionary<int, object> _nodes;
/// <summary>
/// The Id of the node.
/// </summary>
/// <remarks>Can't change.</remarks>
private readonly int _id;
/// <summary>
/// The connections of the node.
/// </summary>
protected readonly Dictionary<int, Node> _connections;
static Node()
{
_nodes = new Dictionary<int, object>();
}
protected Node(int id)
{
// Try register the Id provided
if (_nodes.ContainsKey(id))
{
// If we fail to add it, it means another Node has the same Id already.
throw new ArgumentException($"The id {id} is already in use", nameof(id));
}
_nodes.Add(id, null);
// Store the Id for future reference
_id = id;
_connections = new Dictionary<int, Node>();
}
~Node()
{
// Try to release the Id
// AppDomain unload could be happening
// Any reference could have been set to null
// Do not start async operations
// Do not throw exceptions
// You may, if you so desire, make Node IDisposable, and dispose including this code
var nodes = _nodes;
if (nodes != null)
{
nodes.Remove(Id);
}
}
/// <summary>
/// The Id of the Node
/// </summary>
public int Id { get => _id; }
/// <summary>
/// Connects nodes, bidirectionally.
/// Connect(x, y) is equivalent to Connect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static void Connect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Bidirectional
x._connections[y.Id] = y;
y._connections[x.Id] = x;
}
/// <summary>
/// Disconnects nodes, bidirectionally.
/// Disconnect(x, y) is equivalent to Disconnect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static void Disconnect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Short circuit
if (y._connections.ContainsKey(x.Id) && x._connections.ContainsKey(y.Id))
{
// Bidirectional
x._connections.Remove(y.Id);
y._connections.Remove(x.Id);
}
}
protected abstract void Recieve(Packet value);
}
Note: I didn't add anything to prevent a connection from a Node to itself
I have left Recieve abstract for you to implement. Sink will probably just log the messages, while the SensorNode will have to check the destination and fordward the message.
To send a message from a node to another, use the field _connections. The key is theidof the connectedNode. Thefore, if you want to broadcast, you can iterate over_connections`. If you want to run them in parallel, I have a thread-safe version below.
I have considered that you may need to attach information to the connections (such as wight / distance / cost / delay / latency). If that's the case, consider to create a Connection class and make _connections a dictionary of it. The pragmatic advantage it would have is that you may add the same Connection object to both Nodes and then updates to it will be visible to them both. Or just use Tuple or add more dictionaries, whatever, I don't care.
It took me a while to figure out a good thread-safe implementation. If it used Monitor it would block reads to the connections dictionary, which you need to do to send Pakets, so that's not good. A Read-Write lock is a bit better, but it may result in starving the Connect and Disconnect methods.
What I've come up with is a good old state machine. I added another dictionary to keep the state. Made all the dictionaries ConcurrentDictionary to allow parallel operations and to be able to modify the state atomically.
The code is the following:
abstract class Node
{
/// <summary>
/// Set of all the ids.
/// </summary>
private static readonly ConcurrentDictionary<int, object> _nodes;
/// <summary>
/// The Id of the node.
/// </summary>
/// <remarks>Can't change.</remarks>
private readonly int _id;
/// <summary>
/// The connections of the node.
/// </summary>
protected readonly ConcurrentDictionary<int, Node> _connections;
/// <summary>
/// Status of the connection for synchronization
/// </summary>
private readonly ConcurrentDictionary<int, int> _connectionStatus;
private const int _connecting = 0;
private const int _connected = _connecting + 1;
private const int _disconnecting = _connected + 1;
static Node()
{
_nodes = new ConcurrentDictionary<int, object>();
}
protected Node(int id)
{
// Try register the Id provided
if (!_nodes.TryAdd(id, null))
{
// If we fail to add it, it means another Node has the same Id already.
throw new ArgumentException($"The id {id} is already in use", nameof(id));
}
// Store the Id for future reference
_id = id;
_connections = new ConcurrentDictionary<int, Node>();
_connectionStatus = new oncurrentDictionary<int, int>();
}
~Node()
{
// Try to release the Id
// AppDomain unload could be happening
// Any reference could have been set to null
// Do not start async operations
// Do not throw exceptions
// You may, if you so desire, make Node IDisposable, and dispose including this code
var nodes = _nodes;
if (nodes != null)
{
nodes.TryRemove(Id, out object waste);
}
}
/// <summary>
/// The Id of the Node
/// </summary>
public int Id { get => _id; }
/// <summary>
/// Connects nodes, bidirectionally.
/// Connect(x, y) is equivalent to Connect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static bool Connect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Bidirectional
// Take nodes in order of Id, for syncrhonization
var a = x;
var b = y;
if (b.Id < a.Id)
{
a = y;
b = x;
}
if (a._connectionStatus.TryAdd(b.Id, _connecting)
&& b._connectionStatus.TryAdd(a.Id, _connecting))
{
a._connections[b.Id] = b;
b._connections[a.Id] = a;
a._connectionStatus[b.Id] = _connected;
b._connectionStatus[a.Id] = _connected;
return true;
}
return false;
}
/// <summary>
/// Disconnects nodes, bidirectionally.
/// Disconnect(x, y) is equivalent to Disconnect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static bool Disconnect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Short circuit
if (!y._connections.ContainsKey(x.Id) && !x._connections.ContainsKey(y.Id))
{
return false;
}
// Take nodes in order of Id, for syncrhonization
var a = x;
var b = y;
if (b.Id < a.Id)
{
a = y;
b = x;
}
if (a._connectionStatus.TryUpdate(b.Id, _disconnecting, _connected)
&& b._connectionStatus.TryUpdate(a.Id, _disconnecting, _connected))
{
a._connections.TryRemove(b.Id, out x);
b._connections.TryRemove(a.Id, out y);
int waste;
a._connectionStatus.TryRemove(b.Id, out waste);
b._connectionStatus.TryRemove(a.Id, out waste);
return true;
}
return false;
}
protected abstract void Recieve(Packet value);
}
Threading chatter:
Connect and Disconnect must try to operate on the same order, which is why I have ordered by Id. If they didn't operate on the same order, concurrent execution of Connect and Disconnect might result in unidirectional connection.
If you thread are trying to add the same connection, only one will success (due to TryAdd). If two threads where trying to remove the same connection, only one will success (due to TryUpdate). If the connection exists, Connect will fail. If the connction doesn't exist Disconnect will fail.
If Connect and Disconnect happen concurrently and the connection existed, Connect will not be able to add it and fail unless Disconnect manages to remove it first. If the connection didn't exist, Disconnect will fail unless Connect manages to add it first.
The status _connecting and _disconnecting are there to prevent Connect and Disconnect to see the situation where the connectin exist in one direction but not in the other.
No thread will ever have to wait for another thread to finish. And there is no need for syncrhonization when only reading _connections.
While, in theory a thread that is only reading _connections may be able to see a situation where a connection exists only in one direction, that thread will not be able to send Packet in both directions at the same time. Thefore from the point of view of that thread, the connection was added or removed between its attempts to send Packet.
There is no method to verify if a connection exists, such method would not be reliable because as soon as a thread checks a connection exists, another thread may remove the connection before the first one is able to use it. Preventing a connection from being removed was not part of the requirements, yet it can be added as another connection status.
You can use aggregation relation to achieve what you need. Assuming that any sink can connect two and only tho nodes, every sink class has to contain two properties of type SensorNode. For example:
public class Sink
{
public SensorNode Node1 { get; set; }
public SensorNode Node1 { get; set; }
//...
}
This allows you to control relation between nodes, so you have access to every node, which are connected through sinks. Calling methods on this objects allows you to initiate interaction between objects. BTW, SensorNode class can also contain reference to a list of all its sinks in order to interact with them from it's own methods:
public class SensorNode
{
public List<Sink> ConnectedSinks { get; set; }
}
PS: It is not a very good idea to use public fields in OO Languages, so you'd better consider using public properties instead.
I have a Silverlight 5 browser application.
There is a class
public class ActivityControl:UserControl {
public void LoadSubControls() {
//Creates Other UserControls, does calculations and is very slow..No refactoring..
}
}
I need to create multiple instances of this class and call the method LoadSubControls on runtime.
public class BasicContainer:UserControl {
public void CreateMultipleActivityControls() {
for (int i = 0; i < 1000; i++) {
ActivityControl c = new ActivityControl(); ====> I need to call this in a different thread but causes Invalid Cross Thread Exception
c.LoadSubControls();
}
}
}
Is there any way to create multiple UI Threads in order to avoid invalid cross thread exception?
I need multithreading for performance reasons and because the method call is very slow and the UI freezes.
Is there any way to call method SetSyncronizationContext (which is [SecurityCritical]) in Silverlight?
There is no avoiding creating these controls on the UI thread, but you could take advantage of System.Threading.Tasks.Task from Task Parallel Library (TPL) to allow for asynchronous operations.
I've been able to do something like this in silverlight 5 with a structure like this. Got the original idea looking at the source for Caliburn.Micro.
The following is a subset that applies to what you want.
public interface IPlatformProvider {
/// <summary>
/// Executes the action on the UI thread asynchronously.
/// </summary>
/// <param name = "action">The action to execute.</param>
System.Threading.Tasks.Task OnUIThreadAsync(Action action);
}
Here is the implementation.
/// <summary>
/// A <see cref="IPlatformProvider"/> implementation for the XAML platfrom (Silverlight).
/// </summary>
public class XamlPlatformProvider : IPlatformProvider {
private Dispatcher dispatcher;
public XamlPlatformProvider() {
dispatcher = System.Windows.Deployment.Current.Dispatcher;
}
private void validateDispatcher() {
if (dispatcher == null)
throw new InvalidOperationException("Not initialized with dispatcher.");
}
/// <summary>
/// Executes the action on the UI thread asynchronously.
/// </summary>
/// <param name = "action">The action to execute.</param>
public Task OnUIThreadAsync(System.Action action) {
validateDispatcher();
var taskSource = new TaskCompletionSource<object>();
System.Action method = () => {
try {
action();
taskSource.SetResult(null);
} catch (Exception ex) {
taskSource.SetException(ex);
}
};
dispatcher.BeginInvoke(method);
return taskSource.Task;
}
}
You could either go down the constructor DI route to pass in the provider or use a static locator pattern like this.
/// <summary>
/// Access the current <see cref="IPlatformProvider"/>.
/// </summary>
public static class PlatformProvider {
private static IPlatformProvider current = new XamlPlatformProvider();
/// <summary>
/// Gets or sets the current <see cref="IPlatformProvider"/>.
/// </summary>
public static IPlatformProvider Current {
get { return current; }
set { current = value; }
}
}
Now you should be able to make your calls without blocking the main thread and freezing the UI
public class BasicContainer : UserControl {
public async Task CreateMultipleActivityControls() {
var platform = PlatformProvider.Current;
for (var i = 0; i < 1000; i++) {
await platform.OnUIThreadAsync(() => {
var c = new ActivityControl();
c.LoadSubControls();
});
}
}
}
if making multiple calls to the dispatcher caused any performance issues you could instead move the entire process to one acync call.
public class BasicContainer : UserControl {
public async Task CreateMultipleActivityControls() {
var platform = PlatformProvider.Current;
await platform.OnUIThreadAsync(() => {
for (var i = 0; i < 1000; i++) {
var c = new ActivityControl();
c.LoadSubControls();
}
});
}
}
Can anyone help, I am having problems using the auto-mocking that is available between Ninject and NSubstitute, actually the package is a ninject packaged called Ninject.MockingKernel.NSubstitute which should allow me to use Ninject to create mocks and return instances with mocks injected.
There seems to be a few examples for Moq and Rhinomocks but I don't see any for NSubstitute.
What I have so far is
this.kernel = new NSubstituteMockingKernel();
var summaryService = this.kernel.GetMock<IMyService>(); // GetMock not available
Anybody using it?
Here are a couple of examples adapted from the source code:
[TestFixture]
public class Tests
{
/// <summary>
/// Mocks are singletons.
/// </summary>
[Test]
public void MocksAreSingletons()
{
using (var kernel = new NSubstituteMockingKernel())
{
var firstReference = kernel.Get<IDummyService>();
var secondReference = kernel.Get<IDummyService>();
firstReference.Should().BeSameAs(secondReference);
}
}
/// <summary>
/// Real objects are created for auto bindable types.
/// </summary>
[Test]
public void RealObjectsAreCreatedForAutoBindableTypes()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance = kernel.Get<DummyClass>();
instance.Should().NotBeNull();
}
}
/// <summary>
/// Reals objects are singletons.
/// </summary>
[Test]
public void RealObjectsAreSingletons()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance1 = kernel.Get<DummyClass>();
var instance2 = kernel.Get<DummyClass>();
instance1.Should().BeSameAs(instance2);
}
}
/// <summary>
/// The injected dependencies are actually mocks.
/// </summary>
[Test]
public void TheInjectedDependenciesAreMocks()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance = kernel.Get<DummyClass>();
instance.DummyService.Do();
instance.DummyService.Received().Do();
}
}
public interface IDummyService
{
void Do();
}
public class DummyClass
{
public DummyClass(IDummyService dummyService)
{
this.DummyService = dummyService;
}
public IDummyService DummyService { get; set; }
}
}
Given the following implementation of mutable and immutable types, is there a way to avoid duplicate code (mainly the duplicate properties)?
I'd like to work with immutable type by default unless a mutable type is required (e.g. when binding to UI elements).
We're using .NET framework 4.0, but plan switching to 4.5 soon.
public class Person {
public string Name { get; private set; }
public List<string> Jobs { get; private set; } // Change to ReadOnlyList<T>
public Person() {}
public Person(Mutable m) {
Name = m.Name;
}
public class Mutable : INotifyPropertyChanged {
public string Name { get; set; }
public List<string> Jobs { get; set; }
public Mutable() {
Jobs = new List<string>();
}
public Mutable(Person p) {
Name = p.Name;
Jobs = new List<string>(p.Jobs);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName) {
// TODO: implement
}
}
}
public class Consumer {
public Consumer() {
// We can use object initializers :)
Person.Mutable m = new Person.Mutable {
Name = "M. Utable"
};
// Consumers can happily mutate away....
m.Name = "M. Utated";
m.Jobs.Add("Herper");
m.Jobs.Add("Derper");
// But the core of our app only deals with "realio-trulio" immutable types.
// Yey! Have constructor with arity of one as opposed to
// new Person(firstName, lastName, email, address, im, phone)
Person im = new Person(m);
}
}
I made something that does what you ask recently (using T4 templates), so it is absolutely possible:
https://github.com/xaviergonz/T4Immutable
For example, given this:
[ImmutableClass(Options = ImmutableClassOptions.IncludeOperatorEquals)]
class Person {
private const int AgeDefaultValue = 18;
public string FirstName { get; }
public string LastName { get; }
public int Age { get; }
[ComputedProperty]
public string FullName {
get {
return FirstName + " " + LastName;
}
}
}
It will automatically generate for you in a separate partial class file the following:
A constructor such as public Person(string firstName, string
lastName, int age = 18) that will initialize the values.
Working implementations for Equals(object other) and Equals(Person other).
Also it will add the IEquatable interface for you. Working
implementations for operator== and operator!=
A working implementation of GetHashCode() A better ToString() with output such as "Person { FirstName=John, LastName=Doe, Age=21 }"
A Person With(...) method that can be used to generate a new immutable clone with 0 or more properties changed (e.g. var janeDoe = johnDoe.With(firstName: "Jane", age: 20)
So it will generate this (excluding some redundant attributes):
using System;
partial class Person : IEquatable<Person> {
public Person(string firstName, string lastName, int age = 18) {
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
_ImmutableHashCode = new { this.FirstName, this.LastName, this.Age }.GetHashCode();
}
private bool ImmutableEquals(Person obj) {
if (ReferenceEquals(this, obj)) return true;
if (ReferenceEquals(obj, null)) return false;
return T4Immutable.Helpers.AreEqual(this.FirstName, obj.FirstName) && T4Immutable.Helpers.AreEqual(this.LastName, obj.LastName) && T4Immutable.Helpers.AreEqual(this.Age, obj.Age);
}
public override bool Equals(object obj) {
return ImmutableEquals(obj as Person);
}
public bool Equals(Person obj) {
return ImmutableEquals(obj);
}
public static bool operator ==(Person a, Person b) {
return T4Immutable.Helpers.AreEqual(a, b);
}
public static bool operator !=(Person a, Person b) {
return !T4Immutable.Helpers.AreEqual(a, b);
}
private readonly int _ImmutableHashCode;
private int ImmutableGetHashCode() {
return _ImmutableHashCode;
}
public override int GetHashCode() {
return ImmutableGetHashCode();
}
private string ImmutableToString() {
var sb = new System.Text.StringBuilder();
sb.Append(nameof(Person) + " { ");
var values = new string[] {
nameof(this.FirstName) + "=" + T4Immutable.Helpers.ToString(this.FirstName),
nameof(this.LastName) + "=" + T4Immutable.Helpers.ToString(this.LastName),
nameof(this.Age) + "=" + T4Immutable.Helpers.ToString(this.Age),
};
sb.Append(string.Join(", ", values) + " }");
return sb.ToString();
}
public override string ToString() {
return ImmutableToString();
}
private Person ImmutableWith(T4Immutable.WithParam<string> firstName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<string> lastName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<int> age = default(T4Immutable.WithParam<int>)) {
return new Person(
!firstName.HasValue ? this.FirstName : firstName.Value,
!lastName.HasValue ? this.LastName : lastName.Value,
!age.HasValue ? this.Age : age.Value
);
}
public Person With(T4Immutable.WithParam<string> firstName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<string> lastName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<int> age = default(T4Immutable.WithParam<int>)) {
return ImmutableWith(firstName, lastName, age);
}
}
And there are some more features as explained in the project page.
PS: If you want a property that's a list of other immutable objects just add:
public ImmutableList<string> Jobs { get; }
No, there's no easy way to avoid duplicate code.
What you've implemented is effectivly the builder pattern. The .NET StringBuilder class follows the same approach.
The support for immutable types in C# is a bit lacking, and could do with some language specific features to make it easier. Having to create a builder is a real pain, as you've discovred. An alternative is to have a constructor that takes all the values, but you tend to end up with the mother of all constructors, which makes the code unreadable.
Since the properties don't have the same visibility, this is not duplicate code. If their visibilty were the same, Person could inherit from Mutable to avoid duplication. Right now, I don't think there is code to factorize in what you show.
Think about using code generation to map each mutable to its immutable equivalent.
I personally like T4 code generation, aided by T4Toolbox library.
You can quite easily parse your code using EnvDTE.
You can find tons of high-quality information about T4 on Oleg Sych blog
http://www.olegsych.com/
Code generation could be hard to handle in the beginning, but it solves the infamous issue of the code-that-must-be-duplicated.
One for your consideration depending on if you're creating a public facing API is to consider 'popcicle immutability' as discussed by Eric Lippert. The nice thing about this is you don't need any duplication at all.
I've used something in reverse, my classes are mutable until a certain point when some calculations are going to occur at which point I call a Freeze() method. All changes to properties call a BeforeValueChanged() method, which if frozen throws an exception.
What you need is something whereby the classes are frozen by default, and you unfreeze them if you need them mutable. As others have mentioned if frozen you need to be returning read only copies of lists etc.
Here's an example of a little class I put together:
/// <summary>
/// Defines an object that has a modifiable (thawed) state and a read-only (frozen) state
/// </summary>
/// <remarks>
/// All derived classes should call <see cref="BeforeValueChanged"/> before modifying any state of the object. This
/// ensures that a frozen object is not modified unexpectedly.
/// </remarks>
/// <example>
/// This sample show how a derived class should always use the BeforeValueChanged method <see cref="BeforeValueChanged"/> method.
/// <code>
/// public class TestClass : Freezable
/// {
/// public String Name
/// {
/// get { return this.name; }
/// set
/// {
/// BeforeValueChanged();
/// this.name = name;
/// }
/// }
/// private string name;
/// }
/// </code>
/// </example>
[Serializable]
public class Freezable
{
#region Locals
/// <summary>Is the current instance frozen?</summary>
[NonSerialized]
private Boolean _isFrozen;
/// <summary>Can the current instance be thawed?</summary>
[NonSerialized]
private Boolean _canThaw = true;
/// <summary>Can the current instance be frozen?</summary>
[NonSerialized]
private Boolean _canFreeze = true;
#endregion
#region Properties
/// <summary>
/// Gets a value that indicates whether the object is currently modifiable.
/// </summary>
/// <value>
/// <c>true</c> if this instance is frozen; otherwise, <c>false</c>.
/// </value>
public Boolean IsFrozen
{
get { return this._isFrozen; }
private set { this._isFrozen = value; }
}
/// <summary>
/// Gets a value indicating whether this instance can be frozen.
/// </summary>
/// <value>
/// <c>true</c> if this instance can be frozen; otherwise, <c>false</c>.
/// </value>
public Boolean CanFreeze
{
get { return this._canFreeze; }
private set { this._canFreeze = value; }
}
/// <summary>
/// Gets a value indicating whether this instance can be thawed.
/// </summary>
/// <value>
/// <c>true</c> if this instance can be thawed; otherwise, <c>false</c>.
/// </value>
public Boolean CanThaw
{
get { return this._canThaw; }
private set { this._canThaw = value; }
}
#endregion
#region Methods
/// <summary>
/// Freeze the current instance.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the instance can not be frozen for any reason.</exception>
public void Freeze()
{
if (this.CanFreeze == false)
throw new InvalidOperationException("The instance can not be frozen at this time.");
this.IsFrozen = true;
}
/// <summary>
/// Does a Deep Freeze for the duration of an operation, preventing it being thawed while the operation is running.
/// </summary>
/// <param name="operation">The operation to run</param>
internal void DeepFreeze(Action operation)
{
try
{
this.DeepFreeze();
operation();
}
finally
{
this.DeepThaw();
}
}
/// <summary>
/// Applies a Deep Freeze of the current instance, preventing it be thawed, unless done deeply.
/// </summary>
internal void DeepFreeze()
{
// Prevent Light Thawing
this.CanThaw = false;
this.Freeze();
}
/// <summary>
/// Applies a Deep Thaw of the current instance, reverting a Deep Freeze.
/// </summary>
internal void DeepThaw()
{
// Enable Light Thawing
this.CanThaw = true;
this.Thaw();
}
/// <summary>
/// Thaws the current instance.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the instance can not be thawed for any reason.</exception>
public void Thaw()
{
if (this.CanThaw == false)
throw new InvalidOperationException("The instance can not be thawed at this time.");
this.IsFrozen = false;
}
/// <summary>
/// Ensures that the instance is not frozen, throwing an exception if modification is currently disallowed.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the instance is currently frozen and can not be modified.</exception>
protected void BeforeValueChanged()
{
if (this.IsFrozen)
throw new InvalidOperationException("Unable to modify a frozen object");
}
#endregion
}