例如,我有一个跟踪商品库存的类。 当股票下跌时,我必须添加一个回调来通知使用它的人股票正在下跌(例如,当剩下的对象不到10个时)。 我明白我必须将回调添加到Remove方法中,但是我如何实现它,以及如何在不使用控制台的情况下实现它呢?
您可以使用委托,也可以使用Mediatr等更复杂的东西
下面是一个工作示例,如果你想查看一下的话:
Blazor聊天https://github.com/datajuggler/blazorchat
此示例需要SQL Server或SQL Server Express。
它使用这个名为订阅者服务的类:
#region using statements
using DataJuggler.Blazor.Components;
using DataJuggler.UltimateHelper.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using BlazorChat.Enumerations;
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<SubscriberMessage> messages;
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>();
Messages = new List<SubscriberMessage>();
}
#endregion
#region Methods
#region BroadcastMessage(SubscriberMessage message)
/// <summary>
/// This method Broadcasts a Message to everyone that ins't blocked.
/// What it actually does is notify the Listener that they need to get new messages.
/// Note To Self: Add Blocked Feature.
/// </summary>
public void BroadcastMessage(SubscriberMessage message)
{
// if the value for HasSubscribers is true
if ((HasSubscribers) && (NullHelper.Exists(message)))
{
// if this is a System Message
if (!message.IsSystemMessage)
{
// if there are already messages
if (ListHelper.HasOneOrMoreItems(messages))
{
// Insert at the top
Messages.Insert(0, message);
}
else
{
// Add this message
Messages.Add(message);
}
}
// Iterate the collection of SubscriberCallback objects
foreach (SubscriberCallback subscriber in Subscribers)
{
// Send to everyone but this user
if ((subscriber.HasCallback) && (subscriber.Id != message.FromId))
{
// to do: Add if not blocked
// send the message
subscriber.Callback(message);
}
}
}
}
#endregion
#region FindSubscriber(Guid id)
/// <summary>
/// This method returns the Subscriber
/// </summary>
public SubscriberCallback FindSubscriber(Guid id)
{
// initial value
SubscriberCallback subscriber = null;
// if the id Guid is set and the Subscribers exist
if ((id != Guid.Empty) && (HasSubscribers))
{
// Set the return value
subscriber = Subscribers.FirstOrDefault(x => x.Id == id);
}
// return value
return subscriber;
}
#endregion
#region GetMessages(Guid id, int count)
/// <summary>
/// This method returns a list of Messages
/// </summary>
public List<SubscriberMessage> GetBroadcastMessages(Guid id, int count)
{
// initial value
List<SubscriberMessage> messages = this.Messages.Where(x => ((!x.IsPrivate) || (x.FromId == id) || (x.ToId == id))).Take(count).ToList();
// return value
return messages;
}
#endregion
#region GetSubscriberNames()
/// <summary>
/// This method returns a list of Subscriber Names ()
/// </summary>
public List<SubscriberCallback> GetSubscriberNames()
{
// initial value
List<SubscriberCallback> subscriberNames = null;
// if the value for HasSubscribers is true
if (HasSubscribers)
{
// Set The return value in alphabetical order
subscriberNames = Subscribers.OrderBy(x => x.Name).ToList();
}
// return value
return subscriberNames;
}
#endregion
#region SendPrivateMessage(SubscriberCallback subscriber, SubscriberMessage message)
/// <summary>
/// This method Send Private Message
/// </summary>
public void SendPrivateMessage(SubscriberCallback subscriber, SubscriberMessage message)
{
// if the message and the subscriber exists and the subscriber has a callback
if ((NullHelper.Exists(message, subscriber)) && (subscriber.HasCallback))
{
// if there are already messages
if (ListHelper.HasOneOrMoreItems(messages))
{
// Insert at the top
Messages.Insert(0, message);
}
else
{
// Add this message
Messages.Add(message);
}
// Send the message to the user
subscriber.Callback(message);
}
}
#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";
message.IsSystemMessage = true;
// 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 Messages
/// <summary>
/// This property gets or sets the value for 'Messages'.
/// </summary>
public List<SubscriberMessage> Messages
{
get { return messages; }
set { messages = value; }
}
#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
}
SubscriberService保留一个订阅者列表,这些订阅者都是这个类SubscriberCallback的一部分,其中包括一个名称,一个Guid Id和一个委托回调。
类SubscriberCallback:
#region using statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
#endregion
namespace BlazorChat
{
#region class SubscriberCallback
/// <summary>
/// This class is used to register a subscriber with the ChatService
/// </summary>
public class SubscriberCallback
{
#region Private Variables
private string name;
private Guid id;
private Callback callback;
private List<Guid> blockedList;
#endregion
#region Constructor
/// <summary>
/// Create a new instance of a SubscriberCallback instance
/// </summary>
public SubscriberCallback(string name)
{
// store the Name
Name = name;
// Create the Id
Id = Guid.NewGuid();
// create a BlockedList
BlockedList = new List<Guid>();
}
#endregion
#region Methods
#region ToString()
/// <summary>
/// This method is used to return the Name of the Subscriber when ToString is called.
/// </summary>
/// <returns></returns>
public override string ToString()
{
// return the Name when ToString is called
return this.Name;
}
#endregion
#endregion
#region Properties
#region BlockedList
/// <summary>
/// This property gets or sets the value for 'BlockedList'.
/// </summary>
public List<Guid> BlockedList
{
get { return blockedList; }
set { blockedList = value; }
}
#endregion
#region Callback
/// <summary>
/// This property gets or sets the value for 'Callback'.
/// </summary>
public Callback Callback
{
get { return callback; }
set { callback = value; }
}
#endregion
#region HasBlockedList
/// <summary>
/// This property returns true if this object has a 'BlockedList'.
/// </summary>
public bool HasBlockedList
{
get
{
// initial value
bool hasBlockedList = (this.BlockedList != null);
// return value
return hasBlockedList;
}
}
#endregion
#region HasCallback
/// <summary>
/// This property returns true if this object has a 'Callback'.
/// </summary>
public bool HasCallback
{
get
{
// initial value
bool hasCallback = (this.Callback != null);
// return value
return hasCallback;
}
}
#endregion
#region HasName
/// <summary>
/// This property returns true if the 'Name' exists.
/// </summary>
public bool HasName
{
get
{
// initial value
bool hasName = (!String.IsNullOrEmpty(this.Name));
// return value
return hasName;
}
}
#endregion
#region Id
/// <summary>
/// This property gets or sets the value for 'Id'.
/// </summary>
public Guid Id
{
get { return id; }
set { id = value; }
}
#endregion
#region Name
/// <summary>
/// This property gets or sets the value for 'Name'.
/// </summary>
public string Name
{
get { return name; }
set { name = value; }
}
#endregion
#endregion
}
#endregion
}
委托类回调:
类回调:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorChat
{
/// <summary>
/// This delegate is used by the SubscriberService to send messages to any subscribers
/// </summary>
/// <returns></returns>
public delegate void Callback(SubscriberMessage message);
}
每个用户连接并注册服务器:
SubscriberCallback callback = new SubscriberCallback(SubscriberName);
callback.Callback = Listen;
callback.Name = SubscriberName;
// Get a message back
SubscriberMessage message = SubscriberService.Subscribe(callback);
Listen方法是SubscriberService回调的方法:
public void Listen(SubscriberMessage message)
{
// if the message exists, same as message != null
if (NullHelper.Exists(message))
{
// if the message is a SystemMessage
if (message.IsSystemMessage)
{
// Get the Names again
this.Names = SubscriberService.GetSubscriberNames();
}
else
{
// Get the Messages
this.Messages = SubscriberService.GetBroadcastMessages(this.Id, DisplayMessagesCount);
}
// Update the UI
Refresh();
}
}
我将发布的最后一件事是订阅者消息,我用它向订阅者发送消息:
#region using statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BlazorChat.Enumerations;
#endregion
namespace BlazorChat
{
#region class SubscriberMessage
/// <summary>
/// This class is used to send information between components / pages.
/// </summary>
public class SubscriberMessage
{
#region Private Variables
private string text;
private Guid fromId;
private Guid toId;
private string fromName;
private string toName;
private object data;
private string valid;
private DateTime sent;
private bool isSystemMessage;
private string invalidReason;
private BubbleColorEnum bubbleColor;
private string imageUrl;
private bool isPrivate;
private DateTime sentTime;
#endregion
#region Methods
#region SetImageUrl()
/// <summary>
/// This method Set Image Url
/// </summary>
public void SetImageUrl()
{
// as long as the BubbleColor is set this will work
if (BubbleColor != BubbleColorEnum.NotSet)
{
// Set the ImageUrl
ImageUrl = "../Images/Bubbles/" + BubbleColor.ToString() + ".png";
}
}
#endregion
#endregion
#region Properties
#region BubbleColor
/// <summary>
/// This property gets or sets the value for 'BubbleColor'.
/// </summary>
public BubbleColorEnum BubbleColor
{
get { return bubbleColor; }
set
{
// set the bubbleColor
bubbleColor = value;
// Set the ImageUrl
SetImageUrl();
}
}
#endregion
#region Data
/// <summary>
/// This property gets or sets the value for 'Data'.
/// </summary>
public object Data
{
get { return data; }
set { data = value; }
}
#endregion
#region FromId
/// <summary>
/// This property gets or sets the value for 'FromId'.
/// </summary>
public Guid FromId
{
get { return fromId; }
set { fromId = value; }
}
#endregion
#region FromName
/// <summary>
/// This property gets or sets the value for 'FromName'.
/// </summary>
public string FromName
{
get { return fromName; }
set { fromName = value; }
}
#endregion
#region HasText
/// <summary>
/// This property returns true if the 'Text' exists.
/// </summary>
public bool HasText
{
get
{
// initial value
bool hasText = (!String.IsNullOrEmpty(this.Text));
// return value
return hasText;
}
}
#endregion
#region ImageUrl
/// <summary>
/// This property gets or sets the value for 'ImageUrl'.
/// </summary>
public string ImageUrl
{
get { return imageUrl; }
set { imageUrl = value; }
}
#endregion
#region InvalidReason
/// <summary>
/// This property gets or sets the value for 'InvalidReason'.
/// </summary>
public string InvalidReason
{
get { return invalidReason; }
set { invalidReason = value; }
}
#endregion
#region IsPrivate
/// <summary>
/// This property gets or sets the value for 'IsPrivate'.
/// </summary>
public bool IsPrivate
{
get { return isPrivate; }
set { isPrivate = value; }
}
#endregion
#region IsSystemMessage
/// <summary>
/// This property gets or sets the value for 'IsSystemMessage'.
/// </summary>
public bool IsSystemMessage
{
get { return isSystemMessage; }
set { isSystemMessage = value; }
}
#endregion
#region Sent
/// <summary>
/// This property gets or sets the value for 'Sent'.
/// </summary>
public DateTime Sent
{
get { return sent; }
set { sent = value; }
}
#endregion
#region SentTime
/// <summary>
/// This property gets or sets the value for 'SentTime'.
/// </summary>
public DateTime SentTime
{
get { return sentTime; }
set { sentTime = value; }
}
#endregion
#region Text
/// <summary>
/// This property gets or sets the value for 'Text'.
/// </summary>
public string Text
{
get { return text; }
set { text = value; }
}
#endregion
#region ToId
/// <summary>
/// This property gets or sets the value for 'ToId'.
/// </summary>
public Guid ToId
{
get { return toId; }
set { toId = value; }
}
#endregion
#region ToName
/// <summary>
/// This property gets or sets the value for 'ToName'.
/// </summary>
public string ToName
{
get { return toName; }
set { toName = value; }
}
#endregion
#region Valid
/// <summary>
/// This property gets or sets the value for 'Valid'.
/// </summary>
public string Valid
{
get { return valid; }
set { valid = value; }
}
#endregion
#endregion
}
#endregion
}
该网站也是直播的,但目前还没有多少人报名:
https://blazorchat.com