I have long process and sometimes I want to return process status.
I have the following code:
public delegate Task DeviceOnSureMdmResetIMEIHandler(TabletWithoutDeviceIdDto sureMdmTablet, string oldIMEI);
public delegate Task LocalTabletGroupIsNotFoundHandler(TabletWithoutDeviceIdDto sureMdmTablet);
public delegate Task ExistingDeviceIsNotTabletHandler(Device device);
public delegate Task ErrorCombiningDevicesHandler(string result);
public interface ISureMdmTabletService
{
List<TabletWithoutDeviceIdDto> Tablets { get; set; }
event DeviceOnSureMdmResetIMEIHandler DeviceOnSureMdmResetIMEIEvent;
event LocalTabletGroupIsNotFoundHandler LocalTabletGroupIsNotFoundEvent;
event ExistingDeviceIsNotTabletHandler ExistingDeviceIsNotTabletEvent;
event ErrorCombiningDevicesHandler ErrorCombiningDevicesEvent;
List<string> DeviceIsChanged(TabletWithoutDeviceIdDto newItem, Device dbDevice);
string ImeiIsChanged(TabletWithoutDeviceIdDto newItem, Tablet dbTablet);
List<string> TabletIsChanged(TabletWithoutDeviceIdDto newItem, Tablet dbTablet);
bool ShouldPhoneNumberBeUpdated(TabletWithoutDeviceIdDto newItem, Device device);
bool ShouldICCIDBeUpdated(TabletWithoutDeviceIdDto newItem, Device device);
bool ShouldIMSIBeUpdated(TabletWithoutDeviceIdDto newItem, Device device);
void UpdateAlreadyExistingTablets();
void AddNewTablets();
void DeletedTablets();
Task DuplicateImeiRecordsAsync();
Task<UpdateTabletsFromSureMdmResultDto> UpdateTabletsSaveChangesAsync();
}
public class SureMdmTabletService : ISureMdmTabletService
{
public event DeviceOnSureMdmResetIMEIHandler DeviceOnSureMdmResetIMEIEvent;
public event LocalTabletGroupIsNotFoundHandler LocalTabletGroupIsNotFoundEvent;
public event ExistingDeviceIsNotTabletHandler ExistingDeviceIsNotTabletEvent;
public event ErrorCombiningDevicesHandler ErrorCombiningDevicesEvent;
private List<TabletWithoutDeviceIdDto> _tablets;
public List<TabletWithoutDeviceIdDto> Tablets
{
get
{
return _tablets;
}
set
{
_tablets = value;
}
}
private List<string> _tabletsIMEI { get; set; }
private List<string> _tabletsIds { get; set; }
private List<Tablet> _alreadyExistsTablets { get; set; }
private List<Tablet> _allTablets { get; set; }
private readonly ICombine2DevicesIntoOneService _combine2DevicesIntoOneService;
private readonly DataContext _dbContext;
private readonly IMapper _mapper;
private DeviceModel _deviceModel;
public SureMdmTabletService(DataContext dbContext, ICombine2DevicesIntoOneService combine2DevicesIntoOneService)
{
// .....
}
public List<string> DeviceIsChanged(TabletWithoutDeviceIdDto newItem, Device dbDevice)
{
// .....
}
public string ImeiIsChanged(TabletWithoutDeviceIdDto newItem, Tablet dbTablet)
{
// .....
}
public List<string> TabletIsChanged(TabletWithoutDeviceIdDto newItem, Tablet dbTablet)
{
// .....
}
// .....
public void UpdateAlreadyExistingTablets()
{
**DeviceOnSureMdmResetIMEIEvent.Invoke(...);**
}
}
and wrapper about it:
public interface ISureMdmTabletUpdateCommandService
{
Task<UpdateTabletsFromSureMdmResultDto> CommandAsync(List<TabletWithoutDeviceIdDto> tablets);
}
public class SureMdmTabletUpdateCommandService : ISureMdmTabletUpdateCommandService
{
private readonly ISureMdmTabletService _sureMdmTabletService;
public SureMdmTabletUpdateCommandService(ISureMdmTabletService sureMdmTabletService)
{
_sureMdmTabletService = sureMdmTabletService;
}
public async Task<UpdateTabletsFromSureMdmResultDto> CommandAsync(List<TabletWithoutDeviceIdDto> tablets)
{
_sureMdmTabletService.Tablets = tablets;
_sureMdmTabletService.UpdateAlreadyExistingTablets();
_sureMdmTabletService.AddNewTablets();
_sureMdmTabletService.DeletedTablets();
await _sureMdmTabletService.DuplicateImeiRecordsAsync();
return await _sureMdmTabletService.UpdateTabletsSaveChangesAsync();
}
}
this wrapper is used by client app:
var resultTablets = await _sureMdmTabletUpdateCommandService.CommandAsync(tablets);
I want to subscribe on events from client app like this:
_sureMdmTabletUpdateCommandService.DeviceOnSureMdmResetIMEIEvent +=
but ISureMdmTabletUpdateCommandService does not have, nested class has it. How to throw these events carefully and without dummy intermediate events inside ISureMdmTabletUpdateCommandService ?
Having wrapper requires you to have all the infrastructure on it and you are not required to have full event there just a intermediate methods to attach and detach so you can do explicit event implementation:
object objectLock = new Object();
event DeviceOnSureMdmResetIMEIHandler DeviceOnSureMdmResetIMEIEvent
{
add
{
lock (objectLock)
{
_sureMdmTabletService.DeviceOnSureMdmResetIMEIEvent += value;
}
}
remove
{
lock (objectLock)
{
_sureMdmTabletService.DeviceOnSureMdmResetIMEIEvent -= value;
}
}
}
the lock is required as += and -= operations are not atomic its read modify write.
Having that sad I do not recommend using events at all. I would just passed as a parameter an Action<TabletWithoutDeviceIdDto, string> not even declaring custom delegate for it. Its just simpler approach and it can event support asynchronous operation if you use Func<TabletWithoutDeviceIdDto, string, Task> in contrast to events.
Related
I have a IService in Xamarin.Forms which looks like so:
namespace MyProject.Main
{
public delegate void XChanged();
public delegate void YChanged();
public delegate void ZChanged();
public interface IOrientationSensor
{
double X { get; set; }
double Y { get; set; }
double Z { get; set; }
event XChanged OnXChanged;
event YChanged OnYChanged;
event ZChanged OnZChanged;
void Start();
void Stop();
}
}
I was first trying put my delegates into the interface - but Visual Studio complained about it - so I read they could be put into the namespace instead.
Now in my Service, iOS implementation I can fire OnChangedX:
[assembly: Dependency(typeof(OrientationSensor)) ]
namespace MyProject.iOS
{
public class OrientationSensor : IOrientationSensor
{
CMMotionManager motionManager = new CMMotionManager();
NSOperationQueue queue = new NSOperationQueue();
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public event XChanged OnXChanged;
public event YChanged OnYChanged;
public event ZChanged OnZChanged;
public void Start()
{
motionManager.StartDeviceMotionUpdates(queue, DataUpdated);
}
public void Stop()
{
motionManager.StopDeviceMotionUpdates();
}
void DataUpdated(CMDeviceMotion data, NSError error)
{
if (data == null)
return;
// OnChangedX() works
// OnChangedY() crashes
// OnChangedZ() crashes
}
}
}
Firing Y and Z crashes with message:
Object reference not set to an instance of an object
... while firing X works.
Can someone help trying to explain why I seem to limited to only using only 1 delegate?
I just realised I had assigned an event handler to OnXChanged, but not to OnYChanged and OnZChanged. Assigning event handlers apparently gives the event values:
public static void UseSensors()
{
var orientationSensor = DependencyService.Get<IOrientationSensor>();
orientationSensor.OnXChanged += () =>
{
};
/* did not realize these where needed for OnChangedY and OnChangedZ to stop being null
orientationSensor.OnYChanged += () =>
{
};
orientationSensor.OnZChanged += () =>
{
};
*/
orientationSensor.Start();
}
I will admit, i am doing homework and i am stuck on this one question (Part A). How do i pass the notice method as reference to the railway signal ? Can't i just find out which class was called in the abstract constructor and then print the class name within the notify method? For example:
RailwayUser
private string className;
public RailwayUser()
{
Type type = this.GetType();
className = type.Name;
}
public void PrintClassName()
{
Console.Writeline(className);
}
RailwaySignal Class
public void Notify()
{
foreach(RailwayUser u in _watches)
{
u.PrintClassName();
u.Notice(State)
}
}
This kind of code / design is flawed, since what it does is RailwayUser, registers the object reference with the _watchers List in the RailWaySignal class, which in turn calls the public Notice method on each user when Notify is invoked, which is not how Event Signaling or Function Pointer works. In fact public _watchers is dangerous, as it can be cleared by any user, though that can be moderated using property access
Code with Issue
public void Notify()
{
foreach(RailwayUser u in _watches)
{
u.PrintClassName();
u.Notice(State)
}
}
Following shall be the actual code using events and delegates:
Correct Version
Code Snippet Online - https://www.jdoodle.com/embed/v0/uEc
void Main()
{
List<RailwayUser> railwayUsers = new List<RailwayUser>();
railwayUsers.Add(new RailwayUser());
railwayUsers.Add(new RailwayUser());
RailwayUser.TestNotification();
}
public enum Colour
{
Red,
Green,
NoSignal
}
public class RailwaySignal
{
public string Name {get; set;}
public RailwaySignal(string railwaySignalName)
{
Name = railwaySignalName;
}
// Delegate for handling event
public delegate void RailwaySignalEventHandler(object source, Colour e);
// Delagate object for handling event
private RailwaySignalEventHandler _railwaySignalEvent;
// Event Accessor
public event RailwaySignalEventHandler RailwaySignalEvent
{
add
{
lock (this)
{
_railwaySignalEvent += value;
}
}
remove
{
lock (this)
{
_railwaySignalEvent -= value;
}
}
}
// Invoke Event for subscribed clients
private void Notify()
{
if (_railwaySignalEvent != null)
_railwaySignalEvent.Invoke(this, Colour.Green);
}
// Test the Event Invocation
public void TestEvent()
{
Notify();
}
}
public class RailwayUser
{
private static RailwaySignal railwaySignal { get; set;} = new RailwaySignal("Signal1");
public RailwayUser()
{
railwaySignal.RailwaySignalEvent += this.Notice;
}
public static void TestNotification()
{
railwaySignal.TestEvent();
}
public void Notice(object sender, Colour color)
{
Console.WriteLine($"Notice Called, Colour is :: {color}, Sender is :: {((RailwaySignal)sender).Name}");
}
}
Result
Notice Called, Colour is :: Green, Sender is :: Signal1
Notice Called, Colour is :: Green, Sender is :: Signal1
Important Details
Signature of the event is, (object source, Colour e) which helps in passing the relevant information across to the RailwayUser called, We now know the RailwaySignal triggering the notification to the RailwayUser and its Colour value
Event / Delegate has same signature as called method (which is the basis of working of Delegate / function pointers)
For simplification RailwayUser is a non abstract class
Event is executed using Notify() method inside the RailwaySignal, we are calling it artificially using TestNotification() inside RailwayUser just for demo purpose, but ideally it shall be internally triggered and shall pass on current state like Colour
Pre-defined delegates like Func, Action are quite often used for similar notification mechanism, They internally works using similar mechanism, though declaring an explicit event which is internally a delegate is a well defined pattern, especially for the Ui controls
Standard events exposed by the .Net framework have the signature object sender, EventArgs e, where EventArgs can wrap all information from Event executor (RailwaySignal) to Event receiver (RailwayUser)
It seem like a Observer pattern.You can pass SubClass which inherit from RailwayUser object instance into RailwaySignal class
Your RailwayUser class need create public abstract void Notice(Colour state) method.
public abstract class RailwayUser
{
private string className;
public RailwayUser()
{
Type type = this.GetType();
className = type.Name;
}
public void PrintClassName()
{
Console.WriteLine(className);
}
public abstract void Notice(Colour state);
}
Driver class can inherit RailwayUser class then override Notice method.
public class Driver : RailwayUser
{
public override void Notice(Colour state)
{
Console.WriteLine($"Driver see the {state.ToString()}");
}
}
There are
List<RailwayUser> _watches contain observable object
use SubScript(RailwayUser user) subscription user on _watches List.
RailwayUser Notify() to invoke all your observable Notify method.
look like this.
public class RailwaySignal
{
private List<RailwayUser> _watches;
public Colour Stata { get; set; }
public RailwaySignal()
{
_watches = new List<RailwayUser>();
}
public void SubScript(RailwayUser user)
{
_watches.Add(user);
}
public void Notify()
{
foreach (RailwayUser u in _watches)
{
u.PrintClassName();
u.Notice(Stata);
}
}
}
sample:https://dotnetfiddle.net/GcdGMy
You can also use event to pass method into RailwaySignal then invoke Notify method.
public enum Colour
{
Green,
Red,
Disable
}
public abstract class RailwayUser
{
private string className;
public RailwayUser()
{
Type type = this.GetType();
className = type.Name;
}
public void PrintClassName()
{
Console.WriteLine(className);
}
public abstract void Notice(Colour state);
}
public class Driver : RailwayUser
{
public override void Notice(Colour state)
{
Console.WriteLine("Driver see the "+ state.ToString());
}
}
public class Controller : RailwayUser
{
public override void Notice(Colour state)
{
Console.WriteLine("Controller see the " + state.ToString());
}
}
public class RailwaySignal
{
public delegate void NoticeEvent(Colour state);
public event NoticeEvent Notifys;
public Colour Stata { get; set; }
public void Notify()
{
if (Notifys != null)
{
Notifys(Stata);
}
}
}
use like this.
RailwaySignal railway = new RailwaySignal() { Stata = Colour.Green};
railway.Notifys += new Driver().Notice;
railway.Notifys += new Controller().Notice;
railway.Notify();
sample : https://dotnetfiddle.net/GcdGMy
I want to triggered my event when my UI call my class, life this :
In my UI i call my class ScanClass with a string parameter
ScanMessage scn = new ScanMessage(message);
In my class ScanMessage i made this :
public class ScanMessage
{
public delegate void OnScanMessageReceived(string message);
public ScanMessage()
{
}
public ScanMessage(string message)
{
MessageReceived(message);
}
public event OnScanMessageReceived MessageReceived;
}
And i made this in my FirstViewModel
public FirstViewModel()
{
var scanMessage = new ScanMessage();
scanMessage.MessageReceived += ScanMessage_MessageReceived;
}
private void ScanMessage_MessageReceived(string message)
{
//Do something
}
Well, if i post here, it's because i have a problem and i can't fix it without help !
Thank.
The reason is the instance of ScanMessage is different. UI class has different instance and VM has different instance. Hence raising event on one instance is not being heard in other one.
If all your ScanMessage needs to do is to broadcast event, you can have its singleton instance
public class ScanMessage
{
public delegate void OnScanMessageReceived(string message);
private static ScanMessage _scanMessage = new ScanMessage();
private ScanMessage()
{
}
public static ScanMessage Instance
{
get
{
return _scanMessage;
}
}
public void BroadCastMessage(string message)
{
MessageReceived(message);
}
public event OnScanMessageReceived MessageReceived;
}
And then from UI you can call like
ScanMessage.Instance.BroadCastMessage(message);
and in your VM you can
public FirstViewModel()
{
ScanMessage.Instance.MessageReceived += ScanMessage_MessageReceived;
}
private void ScanMessage_MessageReceived(string message)
{
//Do something
}
I have Singleton class that get's data from web. And i need to pass those data to classes FirstDerived and SecondDerived. In this case is my class Singleton anti-pattern? Is it normal to use Aggregation relationship between DataSocket and FirstDerived, SecondDerived. Maybe it exist better object oriented solution?
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
}
public class TestViewModel
{
public ObservableCollection<Base> Items { get; set; }
public TestViewModel()
{
DataSocket.Instance.SendDataAsync();
Items = new ObservableCollection<Base>();
Items.Add(new FirstDerived(1, DataSocket.Instance));
Items.Add(new SecondDerived(2, DataSocket.Instance));
}
}
public abstract class Base
{
}
public class FirstDerived : Base, IDisposable
{
public FirstDerived(int id, DataSocket socket)
{
socket.Client += ProcessDataFromSocket;
}
public void ProcessDataFromSocket(string arg)
{
Console.WriteLine("First Derived getting data: {0}", arg.ToString());
}
public void Dispose()
{
throw new NotImplementedException();
}
}
public class SecondDerived : Base, IDisposable
{
public SecondDerived(int id, DataSocket socket)
{
DataSocket.Instance.Client += ProcessDataFromSocket;
}
public void ProcessDataFromSocket(string arg)
{
Console.WriteLine("Second Derived getting data: {0}", arg.ToString());
}
public void Dispose()
{
throw new NotImplementedException();
}
}
public sealed class DataSocket
{
private static DataSocket instance;
public delegate void Messages(string info);
public event Messages Client;
private DataSocket()
{
}
public void SendDataAsync()
{
Action Send = new Action(SendData);
IAsyncResult result = Send.BeginInvoke(null,null);
}
public void SendData()
{
while(true)
{
if (Client != null)
{
System.Threading.Thread.Sleep(3000);
Client("Test");
}
}
}
public static DataSocket Instance
{
get
{
if (instance==null)
{
instance = new DataSocket();
}
return instance;
}
}
}
}
To me it looks like DataSocket is the class that deals with networking, so any code to interact with the network should go there. Don't pass it into a constructor.
Rather, do something more like this sequence;
DataSocket.Instance.SendDataAsync();
Items = new ObservableCollection<Base>();
var data1 = await DataSocket.ReadData();
var data2 = await DataSocket.ReadData();
Items.Add(new FirstDerived(1, data1));
Items.Add(new SecondDerived(2, data2));
This way, your classes don't take a dependency on a global, constantly-changing object.
You might also want to consider some kind of lock statement to make sure that different parts of the code -- say, many different simultaneous web requests -- can't interfere with each other.
I have a List<MyClass> with a N numbers of items. I process with the following code
foreach (var item in myList)
{
ThreadPool.QueueUserWorkItem(DoWorkWithItem, item);
}
private void DoWorkWithItem(object threadContext)
{
///...
}
but i need get report what item was proccessed, where i can get a Event or something for this task
create event and call it after threat iteration finished, like this:
public class ClassWithDelegate
{
public delegate void ProgressReportEventHandler();
public static ProgressReportEventHandler ProgressReport { get; set; };
private void DoWorkWithItem(object threadContext)
{
// angry code
if (ProgressReport != null)
ProgressReport();
}
}
public class Subscriber
{
public Subscriber()
{
ClassWithDelegate.ProgressReport += ProgressReport;
}
public void ProgressReport()
{
//todo
}
}
or use BackgroundWorker, it has this event