Use nullability tags

This commit is contained in:
dotMorten 2019-08-21 10:52:56 -07:00
parent e6c2157cee
commit cb39e30e1f
13 changed files with 75 additions and 53 deletions

View file

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 16
VisualStudioVersion = 15.0.27130.2003 VisualStudioVersion = 16.0.0.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NmeaParser", "NmeaParser", "{1701F3BA-A09C-4706-A612-24FD9340FC18}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NmeaParser", "NmeaParser", "{1701F3BA-A09C-4706-A612-24FD9340FC18}"
EndProject EndProject

View file

@ -29,7 +29,7 @@ namespace NmeaParser
{ {
private static Java.Util.UUID SERIAL_UUID = Java.Util.UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"); private static Java.Util.UUID SERIAL_UUID = Java.Util.UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
private Android.Bluetooth.BluetoothDevice m_device; private Android.Bluetooth.BluetoothDevice m_device;
private BluetoothSocket m_socket; private BluetoothSocket? m_socket;
/// <summary> /// <summary>
/// Gets a list of bluetooth devices that supports serial communication /// Gets a list of bluetooth devices that supports serial communication
@ -51,7 +51,7 @@ namespace NmeaParser
/// <param name="device">The Android Bluetooth Device.</param> /// <param name="device">The Android Bluetooth Device.</param>
public BluetoothDevice(Android.Bluetooth.BluetoothDevice device) public BluetoothDevice(Android.Bluetooth.BluetoothDevice device)
{ {
m_device = device; m_device = device ?? throw new ArgumentNullException(nameof(device));
} }
/// <summary> /// <summary>
@ -80,7 +80,7 @@ namespace NmeaParser
if (stream == null) if (stream == null)
throw new ArgumentNullException("stream"); throw new ArgumentNullException("stream");
stream.Dispose(); stream.Dispose();
m_socket.Dispose(); m_socket?.Dispose();
m_socket = null; m_socket = null;
return Task.FromResult(true); return Task.FromResult(true);
} }

View file

@ -33,9 +33,9 @@ namespace NmeaParser
/// </summary> /// </summary>
public class BluetoothDevice : NmeaDevice public class BluetoothDevice : NmeaDevice
{ {
private Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService m_deviceService; private Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService? m_deviceService;
private Windows.Networking.Proximity.PeerInformation m_devicePeer; private Windows.Networking.Proximity.PeerInformation? m_devicePeer;
private StreamSocket m_socket; private StreamSocket? m_socket;
private bool m_disposeService; private bool m_disposeService;
private SemaphoreSlim m_semaphoreSlim = new SemaphoreSlim(1, 1); private SemaphoreSlim m_semaphoreSlim = new SemaphoreSlim(1, 1);
@ -60,7 +60,7 @@ namespace NmeaParser
/// <param name="disposeService">Whether this devicee should also dispose the RfcommDeviceService provided when this device disposes.</param> /// <param name="disposeService">Whether this devicee should also dispose the RfcommDeviceService provided when this device disposes.</param>
public BluetoothDevice(RfcommDeviceService service, bool disposeService = false) public BluetoothDevice(RfcommDeviceService service, bool disposeService = false)
{ {
m_deviceService = service; m_deviceService = service ?? throw new ArgumentNullException(nameof(service));
m_disposeService = disposeService; m_disposeService = disposeService;
} }
@ -70,7 +70,7 @@ namespace NmeaParser
/// <param name="peer">The peer information device.</param> /// <param name="peer">The peer information device.</param>
public BluetoothDevice(Windows.Networking.Proximity.PeerInformation peer) public BluetoothDevice(Windows.Networking.Proximity.PeerInformation peer)
{ {
m_devicePeer = peer; m_devicePeer = peer ?? throw new ArgumentNullException(nameof(peer));
} }
/// <inheritdoc /> /// <inheritdoc />
@ -95,20 +95,37 @@ namespace NmeaParser
{ {
await socket.ConnectAsync(m_devicePeer.HostName, "1"); await socket.ConnectAsync(m_devicePeer.HostName, "1");
} }
else else if (m_deviceService != null)
{ {
await socket.ConnectAsync(m_deviceService.ConnectionHostName, m_deviceService.ConnectionServiceName); await socket.ConnectAsync(m_deviceService.ConnectionHostName, m_deviceService.ConnectionServiceName);
} }
else
throw new InvalidOperationException();
m_socket = socket; m_socket = socket;
return null; //We're going to use WinRT buffers instead and will handle read/write, so no reason to return a stream. This is mainly done to avoid locking issues reading and writing at the same time
return new DummyStream(); //We're going to use WinRT buffers instead and will handle read/write, so no reason to return a real stream. This is mainly done to avoid locking issues reading and writing at the same time
} }
/// <summary> private class DummyStream : Stream
/// Closes the stream the NmeaDevice is working on top off. {
/// </summary> public override bool CanRead => false;
/// <param name="stream">The stream.</param> public override bool CanSeek => false;
/// <returns></returns> public override bool CanWrite => false;
protected override Task CloseStreamAsync(System.IO.Stream stream) public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override void Flush() => throw new NotSupportedException();
public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
}
/// <summary>
/// Closes the stream the NmeaDevice is working on top off.
/// </summary>
/// <param name="stream">The stream.</param>
/// <returns></returns>
protected override Task CloseStreamAsync(System.IO.Stream stream)
{ {
if(m_socket == null) if(m_socket == null)
throw new InvalidOperationException("No connection to close"); throw new InvalidOperationException("No connection to close");
@ -124,6 +141,8 @@ namespace NmeaParser
// Reading and writing to the Bluetooth serial connection at the same time seems very unstable in UWP, // Reading and writing to the Bluetooth serial connection at the same time seems very unstable in UWP,
// so we use a semaphore to ensure we don't read and write at the same time // so we use a semaphore to ensure we don't read and write at the same time
await m_semaphoreSlim.WaitAsync().ConfigureAwait(false); await m_semaphoreSlim.WaitAsync().ConfigureAwait(false);
if (m_socket == null)
throw new InvalidOperationException("Socket not initialized");
try try
{ {
var r = await m_socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)count, Windows.Storage.Streams.InputStreamOptions.None); var r = await m_socket.InputStream.ReadAsync(buffer.AsBuffer(), (uint)count, Windows.Storage.Streams.InputStreamOptions.None);

View file

@ -27,7 +27,7 @@ namespace NmeaParser
/// </summary> /// </summary>
public abstract class BufferedStreamDevice : NmeaDevice public abstract class BufferedStreamDevice : NmeaDevice
{ {
private BufferedStream m_stream; private BufferedStream? m_stream;
private readonly int m_readSpeed; private readonly int m_readSpeed;
/// <summary> /// <summary>
@ -71,7 +71,7 @@ namespace NmeaParser
/// <returns></returns> /// <returns></returns>
protected override Task CloseStreamAsync(System.IO.Stream stream) protected override Task CloseStreamAsync(System.IO.Stream stream)
{ {
m_stream.Dispose(); m_stream?.Dispose();
return Task.FromResult(true); return Task.FromResult(true);
} }
@ -83,8 +83,8 @@ namespace NmeaParser
private byte[] m_buffer = new byte[0]; private byte[] m_buffer = new byte[0];
private readonly System.Threading.Timer m_timer; private readonly System.Threading.Timer m_timer;
private readonly object lockObj = new object(); private readonly object lockObj = new object();
private string groupToken = null; private string? groupToken = null;
private string lastLineRead = null; private string? lastLineRead = null;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BufferedStream"/> class. /// Initializes a new instance of the <see cref="BufferedStream"/> class.
/// </summary> /// </summary>

View file

@ -63,11 +63,11 @@ namespace NmeaParser.Nmea
/// <summary> /// <summary>
/// Name of origin /// Name of origin
/// </summary> /// </summary>
public string OriginId { get; } public string? OriginId { get; }
/// <summary> /// <summary>
/// Name of destination /// Name of destination
/// </summary> /// </summary>
public string DestinationId { get; } public string? DestinationId { get; }
} }
} }

View file

@ -228,7 +228,7 @@ namespace NmeaParser.Nmea
/// <summary> /// <summary>
/// eference station ID1, range 0000-4095 - Null if talker ID is GN, additional GNS messages follow with GP and/or GL Reference station ID /// eference station ID1, range 0000-4095 - Null if talker ID is GN, additional GNS messages follow with GP and/or GL Reference station ID
/// </summary> /// </summary>
public string DgpsStationId { get; } public string? DgpsStationId { get; }
/// <summary> /// <summary>
/// Navigational status /// Navigational status

View file

@ -29,10 +29,10 @@ namespace NmeaParser
{ {
private readonly object m_lockObject = new object(); private readonly object m_lockObject = new object();
private string m_message = ""; private string m_message = "";
private Stream m_stream; private Stream? m_stream;
private CancellationTokenSource m_cts; private CancellationTokenSource? m_cts;
private bool m_isOpening; private bool m_isOpening;
private Task m_ParserTask; private Task? m_ParserTask;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NmeaDevice"/> class. /// Initializes a new instance of the <see cref="NmeaDevice"/> class.
@ -183,7 +183,9 @@ namespace NmeaParser
private void OnMessageReceived(Nmea.NmeaMessage msg) private void OnMessageReceived(Nmea.NmeaMessage msg)
{ {
Nmea.NmeaMessage[] messageParts = null; if (msg == null)
return;
Nmea.NmeaMessage[]? messageParts = null;
if (msg is IMultiPartMessage multi) if (msg is IMultiPartMessage multi)
{ {
string messageType = msg.MessageType.Substring(2); //We don't care about the two first characters. Ie GPGSV, GLGSV, GAGSV etc are all part of the same multi-part message string messageType = msg.MessageType.Substring(2); //We don't care about the two first characters. Ie GPGSV, GLGSV, GAGSV etc are all part of the same multi-part message
@ -212,8 +214,8 @@ namespace NmeaParser
} }
} }
} }
if (messageParts != null)
MessageReceived?.Invoke(this, new NmeaMessageReceivedEventArgs(msg, messageParts)); MessageReceived?.Invoke(this, new NmeaMessageReceivedEventArgs(msg, messageParts));
} }
private readonly Dictionary<string, Dictionary<int, Nmea.NmeaMessage>> MultiPartMessageCache = new Dictionary<string,Dictionary<int,Nmea.NmeaMessage>>(); private readonly Dictionary<string, Dictionary<int, Nmea.NmeaMessage>> MultiPartMessageCache = new Dictionary<string,Dictionary<int,Nmea.NmeaMessage>>();

View file

@ -27,7 +27,7 @@ namespace NmeaParser
public class NmeaFileDevice : BufferedStreamDevice public class NmeaFileDevice : BufferedStreamDevice
{ {
#if NETFX_CORE #if NETFX_CORE
private Windows.Storage.IStorageFile m_storageFile; private Windows.Storage.IStorageFile? m_storageFile;
#endif #endif
private string m_filename; private string m_filename;
@ -44,8 +44,8 @@ namespace NmeaParser
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NmeaFileDevice"/> class. /// Initializes a new instance of the <see cref="NmeaFileDevice"/> class.
/// </summary> /// </summary>
/// <param name="fileName"></param> /// <param name="storageFile"></param>
public NmeaFileDevice(Windows.Storage.IStorageFile fileName) : this(fileName, 1000) public NmeaFileDevice(Windows.Storage.IStorageFile storageFile) : this(storageFile, 1000)
{ {
} }
#endif #endif
@ -63,12 +63,13 @@ namespace NmeaParser
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NmeaFileDevice"/> class. /// Initializes a new instance of the <see cref="NmeaFileDevice"/> class.
/// </summary> /// </summary>
/// <param name="fileName"></param> /// <param name="storageFile"></param>
/// <param name="readSpeed">The time to wait between each group of lines being read in milliseconds</param> /// <param name="readSpeed">The time to wait between each group of lines being read in milliseconds</param>
public NmeaFileDevice(Windows.Storage.IStorageFile fileName, int readSpeed) public NmeaFileDevice(Windows.Storage.IStorageFile storageFile, int readSpeed)
: base(readSpeed) : base(readSpeed)
{ {
m_storageFile = fileName; m_storageFile = storageFile ?? throw new ArgumentNullException(nameof(storageFile));
m_filename = storageFile.Path;
} }
#endif #endif
@ -79,10 +80,6 @@ namespace NmeaParser
{ {
get get
{ {
#if NETFX_CORE
if (m_storageFile != null)
return m_storageFile.Path;
#endif
return m_filename; return m_filename;
} }
} }

View file

@ -27,9 +27,10 @@ Updated license to Apache 2.0</PackageReleaseNotes>
<PublishRepositoryUrl>true</PublishRepositoryUrl> <PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources> <EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<LangVersion>7.3</LangVersion> <LangVersion>8.0</LangVersion>
<TreatWarningsAsErrors Condition="'$(Configuration)'=='Release'">true</TreatWarningsAsErrors> <TreatWarningsAsErrors Condition="'$(Configuration)'=='Release'">true</TreatWarningsAsErrors>
<CodeAnalysisTreatWarningsAsErrors Condition="'$(Configuration)'=='Release'">true</CodeAnalysisTreatWarningsAsErrors> <CodeAnalysisTreatWarningsAsErrors Condition="'$(Configuration)'=='Release'">true</CodeAnalysisTreatWarningsAsErrors>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.4'"> <PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.4'">
@ -41,11 +42,13 @@ Updated license to Apache 2.0</PackageReleaseNotes>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'monoandroid50'"> <PropertyGroup Condition="'$(TargetFramework)' == 'monoandroid50'">
<DesignTimeBuild>false</DesignTimeBuild> <!-- workaround for MSBuildSdkExtras issue in VS16.2 -->
<DefineConstants>$(DefineConstants);XAMARIN;API_LEVEL_21</DefineConstants> <DefineConstants>$(DefineConstants);XAMARIN;API_LEVEL_21</DefineConstants>
<NoWarn>$(NoWarn);XA0113;XA0114</NoWarn> <NoWarn>$(NoWarn);XA0113;XA0114</NoWarn>
<AndroidEnableGooglePlayStoreChecks>false</AndroidEnableGooglePlayStoreChecks> <AndroidEnableGooglePlayStoreChecks>false</AndroidEnableGooglePlayStoreChecks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'monoandroid70'"> <PropertyGroup Condition="'$(TargetFramework)' == 'monoandroid70'">
<DesignTimeBuild>false</DesignTimeBuild> <!-- workaround for MSBuildSdkExtras issue in VS16.2 -->
<DefineConstants>$(DefineConstants);XAMARIN;API_LEVEL_24</DefineConstants> <DefineConstants>$(DefineConstants);XAMARIN;API_LEVEL_24</DefineConstants>
<NoWarn>$(NoWarn);XA0113;XA0114</NoWarn> <NoWarn>$(NoWarn);XA0113;XA0114</NoWarn>
<AndroidEnableGooglePlayStoreChecks>false</AndroidEnableGooglePlayStoreChecks> <AndroidEnableGooglePlayStoreChecks>false</AndroidEnableGooglePlayStoreChecks>

View file

@ -64,7 +64,7 @@ namespace NmeaParser
{ {
if (Port.IsOpen) if (Port.IsOpen)
Port.Close(); Port.Close();
return Task.FromResult<object>(null); return Task.FromResult<object?>(null);
} }
/// <summary> /// <summary>
@ -90,7 +90,7 @@ namespace NmeaParser
throw new InvalidOperationException("Device not open"); throw new InvalidOperationException("Device not open");
Port.Write(buffer, offset, length); Port.Write(buffer, offset, length);
return Task.FromResult<object>(null); return Task.FromResult<object?>(null);
} }
} }
} }

View file

@ -33,7 +33,7 @@ namespace NmeaParser
/// <param name="stream">The stream.</param> /// <param name="stream">The stream.</param>
public StreamDevice(Stream stream) : base() public StreamDevice(Stream stream) : base()
{ {
m_stream = stream; m_stream = stream ?? throw new ArgumentNullException(nameof(stream));
} }
/// <summary> /// <summary>
@ -64,7 +64,6 @@ namespace NmeaParser
base.Dispose(disposing); base.Dispose(disposing);
if (m_stream != null) if (m_stream != null)
m_stream.Dispose(); m_stream.Dispose();
m_stream = null;
} }
/// <inheritdoc /> /// <inheritdoc />

View file

@ -32,16 +32,18 @@ namespace NmeaParser
/// </summary> /// </summary>
public class SystemNmeaDevice : NmeaDevice public class SystemNmeaDevice : NmeaDevice
{ {
private StringStream stream; private StringStream? stream;
private Listener listener; private Listener? listener;
private LocationManager manager; private LocationManager manager;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SystemNmeaDevice"/> class. /// Initializes a new instance of the <see cref="SystemNmeaDevice"/> class.
/// </summary> /// </summary>
public SystemNmeaDevice() public SystemNmeaDevice(Context context)
{ {
manager = Application.Context.GetSystemService(Context.LocationService) as LocationManager; if (context == null)
throw new ArgumentNullException(nameof(context));
manager = context.GetSystemService(Context.LocationService) as LocationManager ?? throw new InvalidOperationException("Cannot acces the Location Service");
} }
/// <summary> /// <summary>
@ -76,10 +78,10 @@ namespace NmeaParser
{ {
manager.RemoveUpdates(listener); manager.RemoveUpdates(listener);
manager.RemoveNmeaListener(listener); manager.RemoveNmeaListener(listener);
listener.Dispose(); listener?.Dispose();
listener = null; listener = null;
stream.Dispose(); stream.Dispose();
return Task.FromResult<object>(null); return Task.CompletedTask;
} }
private class Listener : Java.Lang.Object, private class Listener : Java.Lang.Object,

View file

@ -96,7 +96,7 @@ namespace SampleApp.Droid
return; return;
launched = true; launched = true;
listener = new NmeaParser.SystemNmeaDevice(); listener = new NmeaParser.SystemNmeaDevice(ApplicationContext);
} }
else //Bluetooth else //Bluetooth
{ {