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/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/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..c49b24c
--- /dev/null
+++ b/R4Utils/Messaging/Message.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Runtime.CompilerServices;
+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 instance
+ ///
+ public MessageContext MessageContext { get; init; }
+
+ ///
+ /// 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; } = (_, _) =>
+ throw new NotImplementedException();
+
+ ///
+ /// 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 message and severity 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,
+ [CallerMemberName] string memberName = "",
+ [CallerFilePath] string sourceFilePath = "",
+ [CallerLineNumber] int sourceLineNumber = 0)
+ {
+ 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)}.");
+
+ (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)
+ {
+ Data = data;
+ MessageContext = messageContext;
+ }
+ }
+}
diff --git a/R4Utils/Messaging/MessageBase.cs b/R4Utils/Messaging/MessageBase.cs
new file mode 100644
index 0000000..096c49a
--- /dev/null
+++ b/R4Utils/Messaging/MessageBase.cs
@@ -0,0 +1,55 @@
+using System;
+using R4Utils.Messaging.Exceptions;
+
+namespace R4Utils.Messaging
+{
+ #if FALSE
+ ///
+ /// 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;
+ }
+ }
+#endif
+}
diff --git a/R4Utils/Messaging/MessageContext.cs b/R4Utils/Messaging/MessageContext.cs
new file mode 100644
index 0000000..96a29b9
--- /dev/null
+++ b/R4Utils/Messaging/MessageContext.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Text;
+using R4Utils.Messaging.Exceptions;
+
+namespace R4Utils.Messaging
+{
+ ///
+ /// Represents the context of a
+ ///
+ public class MessageContext where TEnum : Enum
+ {
+ ///
+ /// The entry of the this in the
+ /// used to create this instance.
+ ///
+ 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());
+ }
+}