From 18046b5f83cb00b6426d1650fa5a96de631850c4 Mon Sep 17 00:00:00 2001 From: Ronto4 <34981840+Ronto4@users.noreply.github.com> Date: Sat, 5 Jun 2021 23:46:50 +0200 Subject: [PATCH 1/2] Add basic messaging --- .../Exceptions/AlreadySetUpException.cs | 15 ++++ .../Messaging/Exceptions/NotSetUpException.cs | 14 ++++ R4Utils/Messaging/Message.cs | 74 +++++++++++++++++++ R4Utils/Messaging/MessageBase.cs | 53 +++++++++++++ R4Utils/Messaging/MessageContext.cs | 15 ++++ 5 files changed, 171 insertions(+) create mode 100644 R4Utils/Messaging/Exceptions/AlreadySetUpException.cs create mode 100644 R4Utils/Messaging/Exceptions/NotSetUpException.cs create mode 100644 R4Utils/Messaging/Message.cs create mode 100644 R4Utils/Messaging/MessageBase.cs create mode 100644 R4Utils/Messaging/MessageContext.cs diff --git a/R4Utils/Messaging/Exceptions/AlreadySetUpException.cs b/R4Utils/Messaging/Exceptions/AlreadySetUpException.cs new file mode 100644 index 0000000..37fd3c2 --- /dev/null +++ b/R4Utils/Messaging/Exceptions/AlreadySetUpException.cs @@ -0,0 +1,15 @@ +using System; + +namespace R4Utils.Messaging.Exceptions +{ + /// + /// Thrown when a set up method has been called more than once. + /// + public class AlreadySetUpException : Exception + { + public AlreadySetUpException(string methodName) + : base($"The method ${methodName} may not be called more than once.") + { + } + } +} diff --git a/R4Utils/Messaging/Exceptions/NotSetUpException.cs b/R4Utils/Messaging/Exceptions/NotSetUpException.cs new file mode 100644 index 0000000..b20e5e6 --- /dev/null +++ b/R4Utils/Messaging/Exceptions/NotSetUpException.cs @@ -0,0 +1,14 @@ +using System; + +namespace R4Utils.Messaging.Exceptions +{ + /// + /// Thrown when using a method that requires set up that was not performed. + /// + public class NotSetUpException : Exception + { + public NotSetUpException(string name) : base($"Calling ${name} requires setting it up first.") + { + } + } +} diff --git a/R4Utils/Messaging/Message.cs b/R4Utils/Messaging/Message.cs new file mode 100644 index 0000000..89a347c --- /dev/null +++ b/R4Utils/Messaging/Message.cs @@ -0,0 +1,74 @@ +using System; +using R4Utils.Messaging.Exceptions; + +namespace R4Utils.Messaging +{ + /// + /// Represents a message sent between methods + /// + /// The type of the value being returned + /// The type of the that is + /// used to infer the + public class Message : MessageBase where TEnum : Enum + { + /// + /// The actual value being returned + /// + public TData Data { get; init; } + + /// + /// The message context containing more information about this + /// + public MessageContext MessageContext { get; init; } + + /// + /// The function returning the for the + /// given and + /// + protected static Func ContextGetter { get; set; } = (enumEntry, data) + => BasicContextGetter(Convert.ToInt32(enumEntry), typeof(TEnum), data); + + /// + /// Whether has already been called without failing + /// + // ReSharper disable once StaticMemberInGenericType + protected static bool AlreadySetUp { get; private set; } = false; + + /// + /// Call this method to set up the message handling for + /// this specific combination of and . + /// MUST be called once before the first can be created. + /// MAY NOT be called thereafter. + /// + /// The function returning the for an element + /// of , given some . + /// Thrown when this method was already called. + public static void SetUp(Func contextGetter) + { + if (AlreadySetUp) + throw new AlreadySetUpException(nameof(SetUp)); + + ContextGetter = contextGetter; + AlreadySetUp = true; + } + + public static Message Create(TData data, TEnum enumEntry) + { + if (AlreadySetUp == false && AlreadyBasicSetUp == false) + throw new NotSetUpException(nameof(Create)); + + if (data is null) + throw new ArgumentNullException(nameof(data), + $"A ${nameof(Message)} may not be created with null ${nameof(data)}."); + + Message message = new(data, ContextGetter(enumEntry, data)); + return message; + } + + protected Message(TData data, MessageContext messageContext) + { + Data = data; + MessageContext = messageContext; + } + } +} diff --git a/R4Utils/Messaging/MessageBase.cs b/R4Utils/Messaging/MessageBase.cs new file mode 100644 index 0000000..0080a60 --- /dev/null +++ b/R4Utils/Messaging/MessageBase.cs @@ -0,0 +1,53 @@ +using System; +using R4Utils.Messaging.Exceptions; + +namespace R4Utils.Messaging +{ + /// + /// Contains information shared for all types + /// + public abstract class MessageBase + { + /// + /// The containing the message context indices + /// + protected static Type MessageContextIndex { get; private set; } = typeof(object); + + /// + /// The function returning the for the index in the enum, provided some data + /// + protected static Func BasicContextGetter { get; private set; } = (_, _, _) + => throw new NotImplementedException(nameof(BasicContextGetter)); + + /// + /// Whether has already been called without failing + /// + protected static bool AlreadyBasicSetUp { get; private set; } = false; + + /// + /// Call this method to set up the message handling. + /// MUST be called once before the first can be created. + /// MAY NOT be called thereafter. + /// + /// The that identifies the + /// instances that may be used. + /// The function returning the for an index + /// in , given some . + /// Thrown when this method was already called. + /// Thrown when is + /// not an . + public static void BasicSetUp(Type enumType, Func basicContextGetter) + { + if (AlreadyBasicSetUp) + throw new AlreadySetUpException(nameof(BasicSetUp)); + + if (enumType.IsEnum == false) + throw new ArgumentException($"The provided ${nameof(Type)} is no ${nameof(Enum)}.", + nameof(enumType)); + + AlreadyBasicSetUp = true; + MessageContextIndex = enumType; + BasicContextGetter = basicContextGetter; + } + } +} diff --git a/R4Utils/Messaging/MessageContext.cs b/R4Utils/Messaging/MessageContext.cs new file mode 100644 index 0000000..3bc5a0f --- /dev/null +++ b/R4Utils/Messaging/MessageContext.cs @@ -0,0 +1,15 @@ +using System; + +namespace R4Utils.Messaging +{ + /// + /// Represents the context of a + /// + public class MessageContext + { + /// + /// The of the used to create this . + /// + public Type EnumerationType { get; init; } + } +} From 84729c7566f1f13a9ac38d060590b8f525c0923c Mon Sep 17 00:00:00 2001 From: Ronto4 <34981840+Ronto4@users.noreply.github.com> Date: Wed, 9 Jun 2021 00:43:28 +0200 Subject: [PATCH 2/2] De-facto remove MessageBase; Populate MessageContext; Introduce MessageException --- .../Messaging/Exceptions/MessageException.cs | 39 ++++++++++ R4Utils/Messaging/Message.cs | 37 +++++---- R4Utils/Messaging/MessageBase.cs | 2 + R4Utils/Messaging/MessageContext.cs | 76 ++++++++++++++++++- 4 files changed, 137 insertions(+), 17 deletions(-) create mode 100644 R4Utils/Messaging/Exceptions/MessageException.cs diff --git a/R4Utils/Messaging/Exceptions/MessageException.cs b/R4Utils/Messaging/Exceptions/MessageException.cs new file mode 100644 index 0000000..b61cb21 --- /dev/null +++ b/R4Utils/Messaging/Exceptions/MessageException.cs @@ -0,0 +1,39 @@ +using System; + +namespace R4Utils.Messaging.Exceptions +{ + /// + /// This may be created from + /// a or a . + /// + public class MessageException : Exception + { + /// + /// Creates an instance from just the without any data. + /// + /// A containing information + /// about the used to create this instance. + public MessageException(string messageInformation) + : base($"The following message was thrown: {messageInformation}") + { + } + + /// + /// Creates an instance from a and some . + /// + /// A containing information + /// about the used to create this instance. + /// The data enclosed in the used + /// to create this instance. + public MessageException(string messageInformation, object data) : base(messageInformation) + { + MessageData = data; + } + + /// + /// The data that was enclosed in the used to create this instance. + /// Is null when just a was used to create this instance. + /// + public object? MessageData { get; init; } = null; + } +} diff --git a/R4Utils/Messaging/Message.cs b/R4Utils/Messaging/Message.cs index 89a347c..c49b24c 100644 --- a/R4Utils/Messaging/Message.cs +++ b/R4Utils/Messaging/Message.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using R4Utils.Messaging.Exceptions; namespace R4Utils.Messaging @@ -9,7 +10,7 @@ namespace R4Utils.Messaging /// The type of the value being returned /// The type of the that is /// used to infer the - public class Message : MessageBase where TEnum : Enum + public class Message/* : MessageBase*/ where TEnum : Enum { /// /// The actual value being returned @@ -17,16 +18,18 @@ public class Message : MessageBase where TEnum : Enum public TData Data { get; init; } /// - /// The message context containing more information about this + /// The message context containing more information about this instance /// - public MessageContext MessageContext { get; init; } + public MessageContext MessageContext { get; init; } /// - /// The function returning the for the - /// given and + /// The function returning the message and severity for an element + /// of , given some . /// - protected static Func ContextGetter { get; set; } = (enumEntry, data) - => BasicContextGetter(Convert.ToInt32(enumEntry), typeof(TEnum), data); + // protected static Func> ContextGetter { get; set; } = (enumEntry, data) + // => BasicContextGetter(Convert.ToInt32(enumEntry), typeof(TEnum), data); + protected static Func ContextGetter { get; set; } = (_, _) => + throw new NotImplementedException(); /// /// Whether has already been called without failing @@ -40,10 +43,11 @@ public class Message : MessageBase where TEnum : Enum /// MUST be called once before the first can be created. /// MAY NOT be called thereafter. /// - /// The function returning the for an element + /// The function returning + /// the message and severity for an element /// of , given some . /// Thrown when this method was already called. - public static void SetUp(Func contextGetter) + public static void SetUp(Func contextGetter) { if (AlreadySetUp) throw new AlreadySetUpException(nameof(SetUp)); @@ -52,20 +56,25 @@ public static void SetUp(Func contextGetter) AlreadySetUp = true; } - public static Message Create(TData data, TEnum enumEntry) + public static Message Create(TData data, TEnum enumEntry, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0) { - if (AlreadySetUp == false && AlreadyBasicSetUp == false) + if (AlreadySetUp == false/* && AlreadyBasicSetUp == false*/) throw new NotSetUpException(nameof(Create)); if (data is null) throw new ArgumentNullException(nameof(data), $"A ${nameof(Message)} may not be created with null ${nameof(data)}."); - Message message = new(data, ContextGetter(enumEntry, data)); - return message; + (string message, int severity) = ContextGetter(enumEntry, data); + MessageContext context = MessageContext.Create(enumEntry, message, severity, + sourceFilePath, memberName, sourceLineNumber); + return new(data, context); } - protected Message(TData data, MessageContext messageContext) + protected Message(TData data, MessageContext messageContext) { Data = data; MessageContext = messageContext; diff --git a/R4Utils/Messaging/MessageBase.cs b/R4Utils/Messaging/MessageBase.cs index 0080a60..096c49a 100644 --- a/R4Utils/Messaging/MessageBase.cs +++ b/R4Utils/Messaging/MessageBase.cs @@ -3,6 +3,7 @@ namespace R4Utils.Messaging { + #if FALSE /// /// Contains information shared for all types /// @@ -50,4 +51,5 @@ public static void BasicSetUp(Type enumType, Func /// Represents the context of a /// - public class MessageContext + public class MessageContext where TEnum : Enum { /// - /// The of the used to create this . + /// The entry of the this in the + /// used to create this instance. /// - public Type EnumerationType { get; init; } + public TEnum ContextIdentifier { get; init; } + + /// + /// The message that can get displayed to the user. + /// + public string MessageText { get; init; } + + /// + /// The severity assigned to this instance. + /// The interpretation of this value is not fixed. + /// + public int Severity { get; init; } + + /// + /// The file containing the caller creating + /// the for which this instance has been created. + /// + public string SourceCompilationUnit { get; init; } + /// + /// The method creating + /// the for which this instance has been created. + /// + public string SourceMethod { get; init; } + /// + /// The line in the in which + /// the for which this instance has been created, + /// was created. + /// + public int SourceLine { get; init; } + + public static MessageContext Create(TEnum enumEntry, string messageText, int severity, + string sourceCompilationUnit, string sourceMethod, int sourceLine) + => new(enumEntry, messageText, severity, sourceCompilationUnit, sourceMethod, sourceLine); + + protected MessageContext(TEnum contextIdentifier, string messageText, int severity, string sourceCompilationUnit, + string sourceMethod, int sourceLine) + { + ContextIdentifier = contextIdentifier; + MessageText = messageText; + Severity = severity; + SourceCompilationUnit = sourceCompilationUnit; + SourceMethod = sourceMethod; + SourceLine = sourceLine; + } + + /// + /// Get all data from this instance as a . + /// + /// A in the form 'Message: ...\n Identifier: ...\n Severity: + /// ...\n Message occurred at ... in line ... in ...'. + public override string ToString() + { + StringBuilder sb = new(); + sb.Append($"Message: \"{MessageText}\""); + sb.Append(Environment.NewLine); + sb.Append($"Identifier: {ContextIdentifier}"); + sb.Append(Environment.NewLine); + sb.Append($"Severity: {Severity}"); + sb.Append(Environment.NewLine); + sb.Append($"Message occurred at '{SourceCompilationUnit} in line {SourceLine} in {SourceMethod}"); + return sb.ToString(); + } + + /// + /// Get a from this instance. + /// + /// The containing the information about this instance. + public MessageException AsException() => new(ToString()); } }