mirror of
https://github.com/dotMorten/NmeaParser.git
synced 2026-01-01 06:10:17 +01:00
Adds ability to register custom messages
This commit is contained in:
parent
231c461129
commit
ea1a45c8ec
|
|
@ -62,25 +62,65 @@ namespace NmeaParser.Nmea
|
|||
{
|
||||
messageTypes = new Dictionary<string, ConstructorInfo>();
|
||||
var typeinfo = typeof(NmeaMessage).GetTypeInfo();
|
||||
foreach (var subclass in typeinfo.Assembly.DefinedTypes.Where(t => t.IsSubclassOf(typeof(NmeaMessage))))
|
||||
RegisterAssembly(typeinfo.Assembly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers messages from a different assembly
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The custom message MUST have a constructor taking a <c>string</c> as first parameter (message type name) and a <c>string[]</c> (message parts) as the second.
|
||||
/// In addition the class must have the <see cref="NmeaMessageTypeAttribute" /> defind on the class.
|
||||
/// </remarks>
|
||||
/// <param name="assembly">The assembly to load custom message types from</param>
|
||||
/// <param name="replace">Set to <c>true</c> if you want to replace already registered type. Otherwise this method will throw.</param>
|
||||
/// <returns>Number of message types found.</returns>
|
||||
public static int RegisterAssembly(Assembly assembly, bool replace = false)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (var subclass in assembly.DefinedTypes.Where(t => t.IsSubclassOf(typeof(NmeaMessage)) && !t.IsAbstract))
|
||||
{
|
||||
var attr = subclass.GetCustomAttribute<NmeaMessageTypeAttribute>(false);
|
||||
if (attr != null)
|
||||
{
|
||||
if (!subclass.IsAbstract)
|
||||
{
|
||||
foreach (var c in subclass.DeclaredConstructors)
|
||||
{
|
||||
var pinfo = c.GetParameters();
|
||||
if (pinfo.Length == 2 && pinfo[0].ParameterType == typeof(string) && pinfo[1].ParameterType == typeof(string[]))
|
||||
{
|
||||
messageTypes.Add(attr.NmeaType, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
RegisterNmeaMessage(subclass, attr.NmeaType, replace);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a specific NMEA Message type
|
||||
/// </summary>
|
||||
/// <param name="typeInfo">TypeInfo for the class being registered</param>
|
||||
/// <param name="nmeaType">The 5-character NMEA Type name (eg <c>GPGLL</c>). If <c>null</c>, it'll expect the <see cref="NmeaMessageTypeAttribute" /> to be declared on the class. </param>
|
||||
/// <param name="replace">Set to <c>true</c> if you want to replace already registered type. Otherwise this method will throw.</param>
|
||||
public static void RegisterNmeaMessage(TypeInfo typeInfo, string nmeaType = "", bool replace = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nmeaType))
|
||||
{
|
||||
var attr = typeInfo.GetCustomAttribute<NmeaMessageTypeAttribute>(false);
|
||||
if (attr == null)
|
||||
throw new ArgumentException("Message does not have a NmeaMessageTypeAttribute and no type name was specified.");
|
||||
nmeaType = attr.NmeaType;
|
||||
if (string.IsNullOrEmpty(nmeaType))
|
||||
{
|
||||
throw new ArgumentException("No NmeaType declared on the NmeaMessageTypeAttribute.");
|
||||
}
|
||||
}
|
||||
foreach (var c in typeInfo.DeclaredConstructors)
|
||||
{
|
||||
var pinfo = c.GetParameters();
|
||||
if (pinfo.Length == 2 && pinfo[0].ParameterType == typeof(string) && pinfo[1].ParameterType == typeof(string[]))
|
||||
{
|
||||
if (!replace && messageTypes.ContainsKey(nmeaType))
|
||||
throw new InvalidOperationException($"Message type {nmeaType} declared in {typeInfo.FullName} is already registered by {messageTypes[nmeaType].DeclaringType.FullName}");
|
||||
messageTypes[nmeaType] = c;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new ArgumentException("Type does not have a constructor with parameters (string,string[])");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -810,5 +810,36 @@ namespace NmeaParser.Tests
|
|||
var zda = (Zda)msg;
|
||||
Assert.AreEqual(new DateTimeOffset(2015, 09, 21, 22, 56, 27, 00, TimeSpan.Zero), zda.FixDateTime);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCustomMessageRegistration()
|
||||
{
|
||||
int count = NmeaMessage.RegisterAssembly(typeof(CustomMessage).Assembly, true);
|
||||
Assert.AreEqual(1, count);
|
||||
var input = "$PTEST,TEST*7C";
|
||||
var msg = NmeaMessage.Parse(input);
|
||||
Assert.IsInstanceOfType(msg, typeof(CustomMessage));
|
||||
var cmsg = (CustomMessage)msg;
|
||||
Assert.AreEqual("TEST", cmsg.Value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(InvalidOperationException))]
|
||||
public void TestCustomMessageDuplicateRegistrationFailure()
|
||||
{
|
||||
int count = NmeaMessage.RegisterAssembly(typeof(CustomMessage).Assembly, true);
|
||||
Assert.AreEqual(1, count);
|
||||
count = NmeaMessage.RegisterAssembly(typeof(CustomMessage).Assembly, false); // This will throw
|
||||
}
|
||||
|
||||
[Nmea.NmeaMessageType("PTEST")]
|
||||
private class CustomMessage : NmeaMessage
|
||||
{
|
||||
public CustomMessage(string type, string[] parameters) : base(type, parameters)
|
||||
{
|
||||
Value = parameters[0];
|
||||
}
|
||||
public string Value { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue