diff --git a/K4AdotNet.Samples.Core.BodyTrackingSpeed/K4AdotNet.Samples.Core.BodyTrackingSpeed.csproj b/K4AdotNet.Samples.Core.BodyTrackingSpeed/K4AdotNet.Samples.Core.BodyTrackingSpeed.csproj index ac89027..c8218d7 100644 --- a/K4AdotNet.Samples.Core.BodyTrackingSpeed/K4AdotNet.Samples.Core.BodyTrackingSpeed.csproj +++ b/K4AdotNet.Samples.Core.BodyTrackingSpeed/K4AdotNet.Samples.Core.BodyTrackingSpeed.csproj @@ -5,6 +5,8 @@ Exe netcoreapp3.1 + 8.0 + enable AnyCPU Core .NET sample console application to measure speed of Body Tracking. K4ABodyTrackingSpeed diff --git a/K4AdotNet.Samples.Core.BodyTrackingSpeed/PopInBackgroundProcessor.cs b/K4AdotNet.Samples.Core.BodyTrackingSpeed/PopInBackgroundProcessor.cs index 0782c8d..71b9200 100644 --- a/K4AdotNet.Samples.Core.BodyTrackingSpeed/PopInBackgroundProcessor.cs +++ b/K4AdotNet.Samples.Core.BodyTrackingSpeed/PopInBackgroundProcessor.cs @@ -44,7 +44,7 @@ public override bool NextFrame() return false; } - tracker.TryEnqueueCapture(capture, Timeout.Infinite); + tracker.TryEnqueueCapture(capture!, Timeout.Infinite); } return true; diff --git a/K4AdotNet.Samples.Core.BodyTrackingSpeed/ProcessingParameters.cs b/K4AdotNet.Samples.Core.BodyTrackingSpeed/ProcessingParameters.cs index 15a34aa..34d1272 100644 --- a/K4AdotNet.Samples.Core.BodyTrackingSpeed/ProcessingParameters.cs +++ b/K4AdotNet.Samples.Core.BodyTrackingSpeed/ProcessingParameters.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; namespace K4AdotNet.Samples.Core.BodyTrackingSpeed @@ -26,7 +27,7 @@ public static bool IsValueLikeToMkvFilePath(string value) return true; } - public string MkvPath { get; private set; } + public string? MkvPath { get; private set; } public bool CpuOnlyMode { get; private set; } public ProcessingImplementation Implementation { get; private set; } public TimeSpan? StartTime { get; private set; } @@ -36,7 +37,7 @@ public bool IsTimeInStartEndInterval(TimeSpan frameTimestamp) => (!StartTime.HasValue || StartTime.Value <= frameTimestamp) && (!EndTime.HasValue || EndTime.Value >= frameTimestamp); - public bool TrySetMkvPath(string value, out string message) + public bool TrySetMkvPath(string value, [NotNullWhen(returnValue: false)] out string? message) { if (string.IsNullOrWhiteSpace(value)) { @@ -70,7 +71,7 @@ public bool TrySetMkvPath(string value, out string message) return true; } - public bool TrySetCpuOnlyMode(string value, out string message) + public bool TrySetCpuOnlyMode(string value, [NotNullWhen(returnValue: false)] out string? message) { if (string.IsNullOrWhiteSpace(value)) { @@ -96,7 +97,7 @@ public bool TrySetCpuOnlyMode(string value, out string message) return false; } - public bool TrySetImplementation(string value, out string message) + public bool TrySetImplementation(string value, [NotNullWhen(returnValue: false)] out string? message) { if (string.IsNullOrWhiteSpace(value)) { @@ -126,7 +127,7 @@ public bool TrySetImplementation(string value, out string message) return false; } - public bool TrySetStartTime(string value, out string message) + public bool TrySetStartTime(string value, [NotNullWhen(returnValue: false)] out string? message) { if (string.IsNullOrWhiteSpace(value)) { @@ -154,7 +155,7 @@ public bool TrySetStartTime(string value, out string message) return true; } - public bool TrySetEndTime(string value, out string message) + public bool TrySetEndTime(string value, [NotNullWhen(returnValue: false)] out string? message) { if (string.IsNullOrWhiteSpace(value)) { diff --git a/K4AdotNet.Samples.Core.BodyTrackingSpeed/Processor.cs b/K4AdotNet.Samples.Core.BodyTrackingSpeed/Processor.cs index 0c32d53..4669290 100644 --- a/K4AdotNet.Samples.Core.BodyTrackingSpeed/Processor.cs +++ b/K4AdotNet.Samples.Core.BodyTrackingSpeed/Processor.cs @@ -4,16 +4,13 @@ namespace K4AdotNet.Samples.Core.BodyTrackingSpeed { internal abstract class Processor : IDisposable { - public static Processor Create(ProcessingParameters processingParameters) + public static Processor Create(ProcessingParameters processingParameters) => processingParameters.Implementation switch { - switch (processingParameters.Implementation) - { - case ProcessingImplementation.SingleThread: return new SingleThreadProcessor(processingParameters); - case ProcessingImplementation.PopInBackground: return new PopInBackgroundProcessor(processingParameters); - case ProcessingImplementation.EnqueueInBackground: return new EnqueueInBackgroundProcessor(processingParameters); - default: throw new NotSupportedException(); - } - } + ProcessingImplementation.SingleThread => new SingleThreadProcessor(processingParameters), + ProcessingImplementation.PopInBackground => new PopInBackgroundProcessor(processingParameters), + ProcessingImplementation.EnqueueInBackground => new EnqueueInBackgroundProcessor(processingParameters), + _ => throw new NotSupportedException(), + }; protected readonly ProcessingParameters processingParameters; protected readonly Record.Playback playback; @@ -24,7 +21,7 @@ public static Processor Create(ProcessingParameters processingParameters) protected Processor(ProcessingParameters processingParameters) { this.processingParameters = processingParameters; - playback = new Record.Playback(processingParameters.MkvPath); + playback = new Record.Playback(processingParameters.MkvPath!); playback.GetRecordConfiguration(out recordConfig); RecordLength = playback.RecordLength; playback.GetCalibration(out calibration); @@ -61,7 +58,7 @@ private void Seek(TimeSpan value) throw new ApplicationException("Cannot seek playback to " + value); } - protected bool IsCaptureInInterval(Sensor.Capture capture) + protected bool IsCaptureInInterval(Sensor.Capture? capture) { if (capture == null) return false; diff --git a/K4AdotNet.Samples.Core.BodyTrackingSpeed/Program.cs b/K4AdotNet.Samples.Core.BodyTrackingSpeed/Program.cs index b39feef..41ad306 100644 --- a/K4AdotNet.Samples.Core.BodyTrackingSpeed/Program.cs +++ b/K4AdotNet.Samples.Core.BodyTrackingSpeed/Program.cs @@ -1,6 +1,7 @@ using K4AdotNet.Sensor; using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace K4AdotNet.Samples.Core.BodyTrackingSpeed { @@ -51,11 +52,11 @@ private static void PrintProcessingStatus(Processor processor) Console.Write($"processed: {processor.TotalFrameCount} with body: {processor.FrameWithBodyCount} in buffer: {processor.QueueSize}"); } - private delegate bool ParameterSetter(string value, out string message); + private delegate bool ParameterSetter(string value, [NotNullWhen(returnValue: false)] out string? message); #region Asking parameters from STDIN - private static ProcessingParameters AskProcessingParameters() + private static ProcessingParameters? AskProcessingParameters() { Console.WriteLine("No command line arguments specified."); Console.WriteLine("Please enter execution parameters:"); @@ -93,7 +94,7 @@ private static bool AskParameter(string prompt, ParameterSetter setter) #region Parsing parameters from command-line arguments - private static ProcessingParameters ParseCommandLineArguments(string[] args) + private static ProcessingParameters? ParseCommandLineArguments(string[] args) { var parameters = new ProcessingParameters(); @@ -143,7 +144,7 @@ private static bool ParseArgument(string[] args, ref int argIndex, ParameterSett var name = args[argIndex]; var value = argIndex + 1 < args.Length ? args[argIndex + 1] : null; - string message = null; + string? message = null; if (value != null && setter(value, out message)) { argIndex++; diff --git a/K4AdotNet.Samples.Core.BodyTrackingSpeed/SingleThreadProcessor.cs b/K4AdotNet.Samples.Core.BodyTrackingSpeed/SingleThreadProcessor.cs index c68d5b7..76bf4d9 100644 --- a/K4AdotNet.Samples.Core.BodyTrackingSpeed/SingleThreadProcessor.cs +++ b/K4AdotNet.Samples.Core.BodyTrackingSpeed/SingleThreadProcessor.cs @@ -30,7 +30,7 @@ public override bool NextFrame() return false; } - tracker.TryEnqueueCapture(capture, Timeout.Infinite); + tracker.TryEnqueueCapture(capture!, Timeout.Infinite); Pop(wait: false); } diff --git a/K4AdotNet.Samples.Core.Recorder/K4AdotNet.Samples.Core.Recorder.csproj b/K4AdotNet.Samples.Core.Recorder/K4AdotNet.Samples.Core.Recorder.csproj index f4d60f2..9c90318 100644 --- a/K4AdotNet.Samples.Core.Recorder/K4AdotNet.Samples.Core.Recorder.csproj +++ b/K4AdotNet.Samples.Core.Recorder/K4AdotNet.Samples.Core.Recorder.csproj @@ -5,6 +5,8 @@ Exe netcoreapp3.1 + 8.0 + enable K4ARecorder diff --git a/K4AdotNet.Samples.Core.Recorder/Options.cs b/K4AdotNet.Samples.Core.Recorder/Options.cs index 61d6b66..49149fd 100644 --- a/K4AdotNet.Samples.Core.Recorder/Options.cs +++ b/K4AdotNet.Samples.Core.Recorder/Options.cs @@ -19,12 +19,12 @@ internal sealed class Options [Option('c', "color-mode", Required = false, Default = "1080p", HelpText = "Set the color sensor mode.\n" + "Available options: 3072p, 2160p, 1536p, 1440p, 1080p, 720p, 720p_NV12, 720p_YUY2, OFF")] - public string ColorMode { get; set; } + public string ColorMode { get; set; } = "1080p"; [Option('d', "depth-mode", Required = false, Default = "NFOV_UNBINNED", HelpText = "Set the depth sensor mode.\n" + "Available options: NFOV_2X2BINNED, NFOV_UNBINNED, WFOV_2X2BINNED, WFOV_UNBINNED, PASSIVE_IR, OFF")] - public string DepthMode { get; set; } + public string DepthMode { get; set; } = "NFOV_UNBINNED"; [Option("depth-delay", Required = false, Default = 0, HelpText = "Set the time offset between color and depth frames in microseconds.\n" + @@ -39,7 +39,7 @@ internal sealed class Options [Value(0, Default = null, Required = false, MetaValue = "output.mkv", HelpText = "Output file name. Default: 'yyyy-MM-dd H_mm_ss.mkv' file in 'My Videos' folder.")] - public string Output { get; set; } + public string? Output { get; set; } public int GetDeviceIndex() { diff --git a/K4AdotNet/BodyTracking/BodyFrame.cs b/K4AdotNet/BodyTracking/BodyFrame.cs index 6903998..83d7395 100644 --- a/K4AdotNet/BodyTracking/BodyFrame.cs +++ b/K4AdotNet/BodyTracking/BodyFrame.cs @@ -45,7 +45,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Creates new reference to the same unmanaged body frame object. /// New object that references exactly to the same underlying unmanaged object as original one. Not . @@ -85,7 +85,7 @@ public BodyFrame DuplicateReference() /// use method. /// /// This property cannot be called for disposed objects. - public Sensor.Capture Capture => children.Register(Sensor.Capture.Create(NativeApi.FrameGetCapture(handle.ValueNotDisposed))); + public Sensor.Capture Capture => children.Register(Sensor.Capture.Create(NativeApi.FrameGetCapture(handle.ValueNotDisposed)))!; /// Non-a-body value on index body map. /// @@ -111,7 +111,7 @@ public BodyFrame DuplicateReference() /// use method. /// /// This property cannot be called for disposed objects. - public Sensor.Image BodyIndexMap => children.Register(Sensor.Image.Create(NativeApi.FrameGetBodyIndexMap(handle.ValueNotDisposed))); + public Sensor.Image BodyIndexMap => children.Register(Sensor.Image.Create(NativeApi.FrameGetBodyIndexMap(handle.ValueNotDisposed)))!; /// Gets the joint information for a particular person index. /// Zero-based index of a tracked body. Must me positive number. Must be less than . @@ -140,7 +140,7 @@ public BodyId GetBodyId(int bodyIndex) return NativeApi.FrameGetBodyId(handle.ValueNotDisposed, (uint)bodyIndex); } - internal static BodyFrame Create(NativeHandles.BodyFrameHandle bodyFrameHandle) + internal static BodyFrame? Create(NativeHandles.BodyFrameHandle? bodyFrameHandle) => bodyFrameHandle != null && !bodyFrameHandle.IsInvalid ? new BodyFrame(bodyFrameHandle) : null; #region Equatable @@ -148,14 +148,14 @@ internal static BodyFrame Create(NativeHandles.BodyFrameHandle bodyFrameHandle) /// Two body frames are equal when they reference to one and the same unmanaged object. /// Another body frame to be compared with this one. Can be . /// if both body frames reference to one and the same unmanaged object. - public bool Equals(BodyFrame bodyFrame) + public bool Equals(BodyFrame? bodyFrame) => !(bodyFrame is null) && bodyFrame.handle.Equals(handle); /// Two body frames are equal when they reference to one and the same unmanaged object. /// Some object to be compared with this one. Can be . /// if is also and they both reference to one and the same unmanaged object. - public override bool Equals(object obj) - => obj is BodyFrame && Equals((BodyFrame)obj); + public override bool Equals(object? obj) + => obj is BodyFrame frame && Equals(frame); /// Uses underlying handle as hash code. /// Hash code. Consistent with overridden equality. @@ -168,7 +168,7 @@ public override int GetHashCode() /// Right part of operator. Can be . /// if equals to . /// - public static bool operator ==(BodyFrame left, BodyFrame right) + public static bool operator ==(BodyFrame? left, BodyFrame? right) => (left is null && right is null) || (!(left is null) && left.Equals(right)); /// To be consistent with . @@ -176,7 +176,7 @@ public override int GetHashCode() /// Right part of operator. Can be . /// if is not equal to . /// - public static bool operator !=(BodyFrame left, BodyFrame right) + public static bool operator !=(BodyFrame? left, BodyFrame? right) => !(left == right); /// Convenient (for debugging needs, first of all) string representation of object as an address of unmanaged object in memory. diff --git a/K4AdotNet/BodyTracking/BodyId.cs b/K4AdotNet/BodyTracking/BodyId.cs index 8ca8ff6..3084164 100644 --- a/K4AdotNet/BodyTracking/BodyId.cs +++ b/K4AdotNet/BodyTracking/BodyId.cs @@ -47,16 +47,14 @@ public bool Equals(int other) /// Overloads to be consistent with . /// Object to be compared with this instance. /// if can be cast to and result is equal to this one. - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is BodyId) - return Equals((BodyId)obj); - if (obj is IConvertible) - return Equals(Convert.ToInt32(obj)); - return false; - } + public override bool Equals(object? obj) + => obj switch + { + null => false, + BodyId _ => Equals((BodyId)obj), + IConvertible _ => Equals(Convert.ToInt32(obj)), + _ => false + }; /// To be consistent with . /// Left part of operator. diff --git a/K4AdotNet/BodyTracking/JointTypes.cs b/K4AdotNet/BodyTracking/JointTypes.cs index a369faf..7a71181 100644 --- a/K4AdotNet/BodyTracking/JointTypes.cs +++ b/K4AdotNet/BodyTracking/JointTypes.cs @@ -96,98 +96,92 @@ public static bool IsRight(this JointType jointType) /// /// See https://docs.microsoft.com/en-us/azure/Kinect-dk/body-joints#joint-hierarchy for details. /// Unknown joint. - public static JointType GetParent(this JointType jointType) + public static JointType GetParent(this JointType jointType) => jointType switch { - switch (jointType) - { - // Spine - case JointType.Pelvis: return JointType.Pelvis; - case JointType.SpineNavel: return JointType.Pelvis; - case JointType.SpineChest: return JointType.SpineNavel; - case JointType.Neck: return JointType.SpineChest; - // Left arm - case JointType.ClavicleLeft: return JointType.SpineChest; - case JointType.ShoulderLeft: return JointType.ClavicleLeft; - case JointType.ElbowLeft: return JointType.ShoulderLeft; - case JointType.WristLeft: return JointType.ElbowLeft; - // Left hand - case JointType.HandLeft: return JointType.WristLeft; - case JointType.HandTipLeft: return JointType.HandLeft; - case JointType.ThumbLeft: return JointType.WristLeft; - // Right arm - case JointType.ClavicleRight: return JointType.SpineChest; - case JointType.ShoulderRight: return JointType.ClavicleRight; - case JointType.ElbowRight: return JointType.ShoulderRight; - case JointType.WristRight: return JointType.ElbowRight; - // Right hand - case JointType.HandRight: return JointType.WristRight; - case JointType.HandTipRight: return JointType.HandRight; - case JointType.ThumbRight: return JointType.WristRight; - // Left leg - case JointType.HipLeft: return JointType.Pelvis; - case JointType.KneeLeft: return JointType.HipLeft; - case JointType.AnkleLeft: return JointType.KneeLeft; - case JointType.FootLeft: return JointType.AnkleLeft; - // Right leg - case JointType.HipRight: return JointType.Pelvis; - case JointType.KneeRight: return JointType.HipRight; - case JointType.AnkleRight: return JointType.KneeRight; - case JointType.FootRight: return JointType.AnkleRight; - // Head and face - case JointType.Head: return JointType.Neck; - case JointType.Nose: return JointType.Head; - case JointType.EyeLeft: return JointType.Head; - case JointType.EyeRight: return JointType.Head; - case JointType.EarLeft: return JointType.Head; - case JointType.EarRight: return JointType.Head; - // Unknown - default: throw new ArgumentOutOfRangeException(nameof(jointType)); - } - } + // Spine + JointType.Pelvis => JointType.Pelvis, + JointType.SpineNavel => JointType.Pelvis, + JointType.SpineChest => JointType.SpineNavel, + JointType.Neck => JointType.SpineChest, + // Left arm + JointType.ClavicleLeft => JointType.SpineChest, + JointType.ShoulderLeft => JointType.ClavicleLeft, + JointType.ElbowLeft => JointType.ShoulderLeft, + JointType.WristLeft => JointType.ElbowLeft, + // Left hand + JointType.HandLeft => JointType.WristLeft, + JointType.HandTipLeft => JointType.HandLeft, + JointType.ThumbLeft => JointType.WristLeft, + // Right arm + JointType.ClavicleRight => JointType.SpineChest, + JointType.ShoulderRight => JointType.ClavicleRight, + JointType.ElbowRight => JointType.ShoulderRight, + JointType.WristRight => JointType.ElbowRight, + // Right hand + JointType.HandRight => JointType.WristRight, + JointType.HandTipRight => JointType.HandRight, + JointType.ThumbRight => JointType.WristRight, + // Left leg + JointType.HipLeft => JointType.Pelvis, + JointType.KneeLeft => JointType.HipLeft, + JointType.AnkleLeft => JointType.KneeLeft, + JointType.FootLeft => JointType.AnkleLeft, + // Right leg + JointType.HipRight => JointType.Pelvis, + JointType.KneeRight => JointType.HipRight, + JointType.AnkleRight => JointType.KneeRight, + JointType.FootRight => JointType.AnkleRight, + // Head and face + JointType.Head => JointType.Neck, + JointType.Nose => JointType.Head, + JointType.EyeLeft => JointType.Head, + JointType.EyeRight => JointType.Head, + JointType.EarLeft => JointType.Head, + JointType.EarRight => JointType.Head, + // Unknown + _ => throw new ArgumentOutOfRangeException(nameof(jointType)), + }; /// Mirrors left joint to appropriate right one and vice versa. Doesn't change central joints like joints of spine, neck, head. /// Joint type asked about. /// Mirrored joint type. - public static JointType Mirror(this JointType jointType) + public static JointType Mirror(this JointType jointType) => jointType switch { - switch (jointType) - { - // Left arm -> Right arm - case JointType.ClavicleLeft: return JointType.ClavicleRight; - case JointType.ShoulderLeft: return JointType.ShoulderRight; - case JointType.ElbowLeft: return JointType.ElbowRight; - case JointType.WristLeft: return JointType.WristRight; - // Left hand -> Right hand - case JointType.HandLeft: return JointType.HandRight; - case JointType.HandTipLeft: return JointType.HandTipRight; - case JointType.ThumbLeft: return JointType.ThumbRight; - // Right arm -> Left arm - case JointType.ClavicleRight: return JointType.ClavicleLeft; - case JointType.ShoulderRight: return JointType.ShoulderLeft; - case JointType.ElbowRight: return JointType.ElbowLeft; - case JointType.WristRight: return JointType.WristLeft; - // Right hand -> Left hand - case JointType.HandRight: return JointType.HandLeft; - case JointType.HandTipRight: return JointType.HandTipLeft; - case JointType.ThumbRight: return JointType.ThumbLeft; - // Left leg -> Right leg - case JointType.HipLeft: return JointType.HipRight; - case JointType.KneeLeft: return JointType.KneeRight; - case JointType.AnkleLeft: return JointType.AnkleRight; - case JointType.FootLeft: return JointType.FootRight; - case JointType.HipRight: return JointType.HipLeft; - // Right leg -> Left leg - case JointType.KneeRight: return JointType.KneeLeft; - case JointType.AnkleRight: return JointType.AnkleLeft; - case JointType.FootRight: return JointType.FootLeft; - // Face - case JointType.EyeLeft: return JointType.EyeRight; - case JointType.EarLeft: return JointType.EarRight; - case JointType.EyeRight: return JointType.EyeLeft; - case JointType.EarRight: return JointType.EarLeft; - // Invariant joints - default: return jointType; - } - } + // Left arm -> Right arm + JointType.ClavicleLeft => JointType.ClavicleRight, + JointType.ShoulderLeft => JointType.ShoulderRight, + JointType.ElbowLeft => JointType.ElbowRight, + JointType.WristLeft => JointType.WristRight, + // Left hand -> Right hand + JointType.HandLeft => JointType.HandRight, + JointType.HandTipLeft => JointType.HandTipRight, + JointType.ThumbLeft => JointType.ThumbRight, + // Right arm -> Left arm + JointType.ClavicleRight => JointType.ClavicleLeft, + JointType.ShoulderRight => JointType.ShoulderLeft, + JointType.ElbowRight => JointType.ElbowLeft, + JointType.WristRight => JointType.WristLeft, + // Right hand -> Left hand + JointType.HandRight => JointType.HandLeft, + JointType.HandTipRight => JointType.HandTipLeft, + JointType.ThumbRight => JointType.ThumbLeft, + // Left leg -> Right leg + JointType.HipLeft => JointType.HipRight, + JointType.KneeLeft => JointType.KneeRight, + JointType.AnkleLeft => JointType.AnkleRight, + JointType.FootLeft => JointType.FootRight, + JointType.HipRight => JointType.HipLeft, + // Right leg -> Left leg + JointType.KneeRight => JointType.KneeLeft, + JointType.AnkleRight => JointType.AnkleLeft, + JointType.FootRight => JointType.FootLeft, + // Face + JointType.EyeLeft => JointType.EyeRight, + JointType.EarLeft => JointType.EarRight, + JointType.EyeRight => JointType.EyeLeft, + JointType.EarRight => JointType.EarLeft, + // Invariant joints + _ => jointType, + }; } } diff --git a/K4AdotNet/BodyTracking/NativeApi.cs b/K4AdotNet/BodyTracking/NativeApi.cs index 166661c..f978f9f 100644 --- a/K4AdotNet/BodyTracking/NativeApi.cs +++ b/K4AdotNet/BodyTracking/NativeApi.cs @@ -24,7 +24,7 @@ internal static class NativeApi public static extern NativeCallResults.Result TrackerCreate( [In] ref Sensor.Calibration sensorCalibration, TrackerConfiguration config, - out NativeHandles.TrackerHandle trackerHandle); + out NativeHandles.TrackerHandle? trackerHandle); // K4ABT_EXPORT void k4abt_tracker_set_temporal_smoothing(k4abt_tracker_t tracker_handle, float smoothing_factor); /// Control the temporal smoothing across frames. @@ -105,7 +105,7 @@ public static extern NativeCallResults.WaitResult TrackerEnqueueCapture( [DllImport(Sdk.BODY_TRACKING_DLL_NAME, EntryPoint = "k4abt_tracker_pop_result", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.WaitResult TrackerPopResult( NativeHandles.TrackerHandle trackerHandle, - out NativeHandles.BodyFrameHandle bodyFrameHandle, + out NativeHandles.BodyFrameHandle? bodyFrameHandle, Timeout timeout); // K4ABT_EXPORT void k4abt_tracker_shutdown(k4abt_tracker_t tracker_handle); diff --git a/K4AdotNet/BodyTracking/Skeleton.cs b/K4AdotNet/BodyTracking/Skeleton.cs index 616b7f8..ccd2124 100644 --- a/K4AdotNet/BodyTracking/Skeleton.cs +++ b/K4AdotNet/BodyTracking/Skeleton.cs @@ -127,45 +127,42 @@ public struct Skeleton : IEnumerable /// public Joint this[JointType index] { - get + get => index switch { - switch (index) - { - case JointType.Pelvis: return Pelvis; - case JointType.SpineNavel: return SpineNavel; - case JointType.SpineChest: return SpineChest; - case JointType.Neck: return Neck; - case JointType.ClavicleLeft: return ClavicleLeft; - case JointType.ShoulderLeft: return ShoulderLeft; - case JointType.ElbowLeft: return ElbowLeft; - case JointType.WristLeft: return WristLeft; - case JointType.HandLeft: return HandLeft; - case JointType.HandTipLeft: return HandTipLeft; - case JointType.ThumbLeft: return ThumbLeft; - case JointType.ClavicleRight: return ClavicleRight; - case JointType.ShoulderRight: return ShoulderRight; - case JointType.ElbowRight: return ElbowRight; - case JointType.WristRight: return WristRight; - case JointType.HandRight: return HandRight; - case JointType.HandTipRight: return HandTipRight; - case JointType.ThumbRight: return ThumbRight; - case JointType.HipLeft: return HipLeft; - case JointType.KneeLeft: return KneeLeft; - case JointType.AnkleLeft: return AnkleLeft; - case JointType.FootLeft: return FootLeft; - case JointType.HipRight: return HipRight; - case JointType.KneeRight: return KneeRight; - case JointType.AnkleRight: return AnkleRight; - case JointType.FootRight: return FootRight; - case JointType.Head: return Head; - case JointType.Nose: return Nose; - case JointType.EyeLeft: return EyeLeft; - case JointType.EarLeft: return EarLeft; - case JointType.EyeRight: return EyeRight; - case JointType.EarRight: return EarRight; - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } + JointType.Pelvis => Pelvis, + JointType.SpineNavel => SpineNavel, + JointType.SpineChest => SpineChest, + JointType.Neck => Neck, + JointType.ClavicleLeft => ClavicleLeft, + JointType.ShoulderLeft => ShoulderLeft, + JointType.ElbowLeft => ElbowLeft, + JointType.WristLeft => WristLeft, + JointType.HandLeft => HandLeft, + JointType.HandTipLeft => HandTipLeft, + JointType.ThumbLeft => ThumbLeft, + JointType.ClavicleRight => ClavicleRight, + JointType.ShoulderRight => ShoulderRight, + JointType.ElbowRight => ElbowRight, + JointType.WristRight => WristRight, + JointType.HandRight => HandRight, + JointType.HandTipRight => HandTipRight, + JointType.ThumbRight => ThumbRight, + JointType.HipLeft => HipLeft, + JointType.KneeLeft => KneeLeft, + JointType.AnkleLeft => AnkleLeft, + JointType.FootLeft => FootLeft, + JointType.HipRight => HipRight, + JointType.KneeRight => KneeRight, + JointType.AnkleRight => AnkleRight, + JointType.FootRight => FootRight, + JointType.Head => Head, + JointType.Nose => Nose, + JointType.EyeLeft => EyeLeft, + JointType.EarLeft => EarLeft, + JointType.EyeRight => EyeRight, + JointType.EarRight => EarRight, + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; set { diff --git a/K4AdotNet/BodyTracking/Tracker.cs b/K4AdotNet/BodyTracking/Tracker.cs index 9d0702a..3dc3f4c 100644 --- a/K4AdotNet/BodyTracking/Tracker.cs +++ b/K4AdotNet/BodyTracking/Tracker.cs @@ -1,5 +1,6 @@ using K4AdotNet.Sensor; using System; +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace K4AdotNet.BodyTracking @@ -75,7 +76,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Shutdown the tracker so that no further capture can be added to the input queue. /// @@ -109,10 +110,10 @@ public void Shutdown() public bool IsQueueFull => queueSize >= MaxQueueSize; /// Raised on increasing of . - public event EventHandler QueueSizeIncreased; + public event EventHandler? QueueSizeIncreased; /// Raised on decreasing of . - public event EventHandler QueueSizeDecreased; + public event EventHandler? QueueSizeDecreased; /// Temporal smoothing across frames (0 - 1). Default value is . /// @@ -162,7 +163,7 @@ public float TemporalSmoothingFactor /// Cannot add capture to the tracker for some unknown reason. See logs for details. public bool TryEnqueueCapture(Capture capture, Timeout timeout = default) { - if (capture == null) + if (capture is null) throw new ArgumentNullException(nameof(capture)); var res = NativeApi.TrackerEnqueueCapture(handle.ValueNotDisposed, Capture.ToHandle(capture), timeout); @@ -254,7 +255,7 @@ public void EnqueueCapture(Capture capture) /// Object was disposed before this call or has been disposed during this call. /// Cannot get body frame for some unknown reason. See logs for details. /// - public bool TryPopResult(out BodyFrame bodyFrame, Timeout timeout = default) + public bool TryPopResult([NotNullWhen(returnValue: true)] out BodyFrame? bodyFrame, Timeout timeout = default) { var res = NativeApi.TrackerPopResult(handle.ValueNotDisposed, out var bodyFrameHandle, timeout); if (res == NativeCallResults.WaitResult.Timeout) @@ -284,7 +285,7 @@ public BodyFrame PopResult() { var res = TryPopResult(out var bodyFrame, Timeout.Infinite); System.Diagnostics.Debug.Assert(res); - return bodyFrame; + return bodyFrame!; } /// Max amount of captures that can be simultaneously in processing pipeline. diff --git a/K4AdotNet/ChildrenDisposer.cs b/K4AdotNet/ChildrenDisposer.cs index 8789b25..ced4feb 100644 --- a/K4AdotNet/ChildrenDisposer.cs +++ b/K4AdotNet/ChildrenDisposer.cs @@ -26,9 +26,9 @@ public void Dispose() } } - public T Register(T child) where T : IDisposablePlus + public T? Register(T? child) where T : class, IDisposablePlus { - if (child == null || child.IsDisposed) + if (child is null || child.IsDisposed) return child; lock (trackedChildren) diff --git a/K4AdotNet/Float2.cs b/K4AdotNet/Float2.cs index ac953eb..fea336c 100644 --- a/K4AdotNet/Float2.cs +++ b/K4AdotNet/Float2.cs @@ -89,7 +89,7 @@ public bool Equals(Float2 other) /// Object to be compared with this vector. /// if is a and is equal to this one. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is null || !(obj is Float2)) return false; diff --git a/K4AdotNet/Float3.cs b/K4AdotNet/Float3.cs index 95979de..52d697a 100644 --- a/K4AdotNet/Float3.cs +++ b/K4AdotNet/Float3.cs @@ -98,7 +98,7 @@ public bool Equals(Float3 other) /// Object to be compared with this vector. /// if is a and is equal to this one. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is null || !(obj is Float3)) return false; diff --git a/K4AdotNet/Float3x3.cs b/K4AdotNet/Float3x3.cs index a2a1cca..a479217 100644 --- a/K4AdotNet/Float3x3.cs +++ b/K4AdotNet/Float3x3.cs @@ -161,7 +161,7 @@ public bool Equals(Float3x3 other) /// Object to be compared with this matrix. /// if is a and is equal to this one. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is null || !(obj is Float3x3)) return false; diff --git a/K4AdotNet/Helpers.cs b/K4AdotNet/Helpers.cs index 93f941a..a8b21b3 100644 --- a/K4AdotNet/Helpers.cs +++ b/K4AdotNet/Helpers.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text; @@ -16,16 +17,16 @@ public static UIntPtr Int32ToUIntPtr(int value) public delegate NativeCallResults.BufferResult GetInByteBufferMethod(T parameter, byte[] data, ref UIntPtr dataSize); - public static bool TryGetValueInByteBuffer(GetInByteBufferMethod getMethod, T parameter, out byte[] result) + public static bool TryGetValueInByteBuffer(GetInByteBufferMethod getMethod, T parameter, + [NotNullWhen(returnValue: true)] out byte[]? result) { var buffer = new byte[0]; var bufferSize = UIntPtr.Zero; - var size = 0; var res = getMethod(parameter, buffer, ref bufferSize); if (res == NativeCallResults.BufferResult.TooSmall) { - size = UIntPtrToInt32(bufferSize); + var size = UIntPtrToInt32(bufferSize); if (size > 1) { buffer = new byte[size]; @@ -44,7 +45,8 @@ public static bool TryGetValueInByteBuffer(GetInByteBufferMethod getMethod return true; } - public static byte[] StringToBytes(string value, Encoding encoding) + [return: NotNullIfNotNull(parameterName: "value")] + public static byte[]? StringToBytes(string? value, Encoding encoding) { if (value == null) return null; @@ -57,7 +59,7 @@ public static byte[] StringToBytes(string value, Encoding encoding) return result; } - public static bool IsAsciiCompatible(string value) + public static bool IsAsciiCompatible(string? value) { if (value == null) return true; @@ -92,7 +94,7 @@ public static int IndexOf(this byte[] array, byte value) return -1; } - public static void CheckTagName(string tagName) + public static void CheckTagName(string? tagName) { if (string.IsNullOrEmpty(tagName)) throw new ArgumentNullException(tagName); @@ -100,7 +102,7 @@ public static void CheckTagName(string tagName) throw new ArgumentException($"Invalid value \"{tagName}\" of {nameof(tagName)}. Tag name must be ALL CAPS and may only contain A-Z, 0-9, '-' and '_'.", nameof(tagName)); } - public static void CheckTrackName(string trackName) + public static void CheckTrackName(string? trackName) { if (string.IsNullOrEmpty(trackName)) throw new ArgumentNullException(trackName); @@ -108,11 +110,10 @@ public static void CheckTrackName(string trackName) throw new ArgumentException($"Invalid value \"{trackName}\" of {nameof(trackName)}. Track name must be ALL CAPS and may only contain A-Z, 0-9, '-' and '_'.", nameof(trackName)); } - private static bool IsValidTagOrTrackName(string tagName) + private static bool IsValidTagOrTrackName(string? tagName) => !string.IsNullOrEmpty(tagName) && tagName.All(chr => IsValidTagOrTrackNameCharacter(chr)); private static bool IsValidTagOrTrackNameCharacter(char chr) => (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr == '-' || chr == '_'; - } } diff --git a/K4AdotNet/K4AdotNet.csproj b/K4AdotNet/K4AdotNet.csproj index ee140ce..5f9b684 100644 --- a/K4AdotNet/K4AdotNet.csproj +++ b/K4AdotNet/K4AdotNet.csproj @@ -3,7 +3,9 @@ - netstandard2.0;net461 + netstandard2.1;netstandard2.0;net461 + 8.0 + enable AnyCPU Three-in-one .NET library to work with Azure Kinect devices. It includes sensor API, recording and playback API, body tracking API. Compatible with .NET Standard 2.0 and .NET Framework 4.6.1 and later. All required binaries from Azure Kinect Sensor SDK (win x64) are included. Samples (WPF, .NET Core and Unity) can be found in the source repository. Kinect Azure .NET K4A Depth Sensor Body Tracking BodyTracking SDK @@ -28,6 +30,23 @@ + + + $(NoWarn);8600;8601;8602;8603;8604 + + + $(NoWarn);0618 + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + package\%(FileName)%(Extension) diff --git a/K4AdotNet/K4AdotNet.xml b/K4AdotNet/K4AdotNet.xml index a26ecc4..2a9b75b 100644 --- a/K4AdotNet/K4AdotNet.xml +++ b/K4AdotNet/K4AdotNet.xml @@ -7660,3 +7660,149 @@ +System.Diagnostics.CodeAnalysis.AllowNullAttribute"> + + Specifies that is allowed as an input even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that is disallowed as an input even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that a method that will never return under any circumstance. + + + + + Initializes a new instance of the class. + + + + + + Specifies that the method will not return if the associated + parameter is passed the specified value. + + + + + Gets the condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Initializes a new instance of the + class with the specified parameter value. + + + The condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Specifies that an output may be even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that when a method returns , + the parameter may be even if the corresponding type disallows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter may be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter may be . + + + + + Specifies that an output is not even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that the output will be non- if the + named parameter is non-. + + + + + Gets the associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Initializes the attribute with the associated parameter name. + + + The associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Specifies that when a method returns , + the parameter will not be even if the corresponding type allows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter will not be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter will not be . + + + + diff --git a/K4AdotNet/Microseconds32.cs b/K4AdotNet/Microseconds32.cs index 2700b47..b07da60 100644 --- a/K4AdotNet/Microseconds32.cs +++ b/K4AdotNet/Microseconds32.cs @@ -89,18 +89,15 @@ public int CompareTo(int otherUsec) /// For details see . /// /// is not comparable with this one. - public int CompareTo(object obj) - { - if (obj is null) - return 1; - if (obj is Microseconds32) - return CompareTo((Microseconds32)obj); - if (obj is TimeSpan) - return CompareTo((TimeSpan)obj); - if (obj is IConvertible) - return CompareTo(Convert.ToInt32(obj)); - throw new ArgumentException("Object is not a Microseconds32 or TimeSpan or integer number", nameof(obj)); - } + public int CompareTo(object? obj) + => obj switch + { + null => 1, + Microseconds32 _ => CompareTo((Microseconds32)obj), + TimeSpan _ => CompareTo((TimeSpan)obj), + IConvertible _ => CompareTo(Convert.ToInt32(obj)), + _ => throw new ArgumentException("Object is not a Microseconds32 or TimeSpan or integer number", nameof(obj)) + }; /// String representation of current instance. /// The format to use or for default format. @@ -112,18 +109,15 @@ public string ToString(string format, IFormatProvider formatProvider) /// Overloads to be consistent with . /// Object to be compared with this instance. /// if can be cast to and result is equal to this one. - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is Microseconds32) - return Equals((Microseconds32)obj); - if (obj is TimeSpan) - return Equals((TimeSpan)obj); - if (obj is IConvertible) - return Equals(Convert.ToInt32(obj)); - return false; - } + public override bool Equals(object? obj) + => obj switch + { + null => false, + Microseconds32 _ => Equals((Microseconds32)obj), + TimeSpan _ => Equals((TimeSpan)obj), + IConvertible _ => Equals(Convert.ToInt32(obj)), + _ => false + }; /// Calculates hash code. /// Hash code. Consistent with overridden equality. diff --git a/K4AdotNet/Microseconds64.cs b/K4AdotNet/Microseconds64.cs index 93a5d79..d3e7d14 100644 --- a/K4AdotNet/Microseconds64.cs +++ b/K4AdotNet/Microseconds64.cs @@ -89,18 +89,15 @@ public int CompareTo(long otherUsec) /// For details see . /// /// is not comparable with this one. - public int CompareTo(object obj) - { - if (obj is null) - return 1; - if (obj is Microseconds64) - return CompareTo((Microseconds64)obj); - if (obj is TimeSpan) - return CompareTo((TimeSpan)obj); - if (obj is IConvertible) - return CompareTo(Convert.ToInt64(obj)); - throw new ArgumentException("Object is not a Microseconds64 or TimeSpan or 64-bit integer number", nameof(obj)); - } + public int CompareTo(object? obj) + => obj switch + { + null => 1, + Microseconds64 microseconds => CompareTo(microseconds), + TimeSpan span => CompareTo(span), + IConvertible _ => CompareTo(Convert.ToInt64(obj)), + _ => throw new ArgumentException("Object is not a Microseconds64 or TimeSpan or 64-bit integer number", nameof(obj)) + }; /// String representation of current instance. /// The format to use or for default format. @@ -112,18 +109,15 @@ public string ToString(string format, IFormatProvider formatProvider) /// Overloads to be consistent with . /// Object to be compared with this instance. /// if can be cast to and result is equal to this one. - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is Microseconds64) - return Equals((Microseconds64)obj); - if (obj is TimeSpan) - return Equals((TimeSpan)obj); - if (obj is IConvertible) - return Equals(Convert.ToInt64(obj)); - return false; - } + public override bool Equals(object? obj) + => obj switch + { + null => false, + Microseconds64 microseconds => Equals(microseconds), + TimeSpan span => Equals(span), + IConvertible _ => Equals(Convert.ToInt64(obj)), + _ => false + }; /// Calculates hash code. /// Hash code. Consistent with overridden equality. diff --git a/K4AdotNet/Nanoseconds64.cs b/K4AdotNet/Nanoseconds64.cs index 28b44c5..95a10aa 100644 --- a/K4AdotNet/Nanoseconds64.cs +++ b/K4AdotNet/Nanoseconds64.cs @@ -92,18 +92,15 @@ public int CompareTo(long otherNsec) /// For details see . /// /// is not comparable with this one. - public int CompareTo(object obj) - { - if (obj is null) - return 1; - if (obj is Nanoseconds64) - return CompareTo((Nanoseconds64)obj); - if (obj is TimeSpan) - return CompareTo((TimeSpan)obj); - if (obj is IConvertible) - return CompareTo(Convert.ToInt64(obj)); - throw new ArgumentException("Object is not a Nanoseconds64 or TimeSpan or 64-bit integer number", nameof(obj)); - } + public int CompareTo(object? obj) + => obj switch + { + null => 1, + Nanoseconds64 nanoseconds => CompareTo(nanoseconds), + TimeSpan span => CompareTo(span), + IConvertible _ => CompareTo(Convert.ToInt64(obj)), + _ => throw new ArgumentException("Object is not a Nanoseconds64 or TimeSpan or 64-bit integer number", nameof(obj)) + }; /// String representation of current instance. /// The format to use or for default format. @@ -115,18 +112,15 @@ public string ToString(string format, IFormatProvider formatProvider) /// Overloads to be consistent with . /// Object to be compared with this instance. /// if can be cast to and result is equal to this one. - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is Nanoseconds64) - return Equals((Nanoseconds64)obj); - if (obj is TimeSpan) - return Equals((TimeSpan)obj); - if (obj is IConvertible) - return Equals(Convert.ToInt64(obj)); - return false; - } + public override bool Equals(object? obj) + => obj switch + { + null => false, + Nanoseconds64 nanoseconds => Equals(nanoseconds), + TimeSpan span => Equals(span), + IConvertible _ => Equals(Convert.ToInt64(obj)), + _ => false + }; /// Calculates hash code. /// Hash code. Consistent with overridden equality. diff --git a/K4AdotNet/NativeHandles/HandleBase.cs b/K4AdotNet/NativeHandles/HandleBase.cs index 9f3958b..7a59e74 100644 --- a/K4AdotNet/NativeHandles/HandleBase.cs +++ b/K4AdotNet/NativeHandles/HandleBase.cs @@ -37,21 +37,21 @@ public override int GetHashCode() /// Two objects are equal when they reference to one and the same unmanaged object. /// Another handle to be compared with this one. Can be . /// if both handles reference to one and the same object. - public bool Equals(HandleBase other) + public bool Equals(HandleBase? other) => !(other is null) && other.handle == handle; /// Two objects are equal when they reference to one and the same unmanaged object. /// Another handle to be compared with this one. Can be . /// if is and they both reference to one and the same object. - public override bool Equals(object obj) - => obj is HandleBase && Equals((HandleBase)obj); + public override bool Equals(object? obj) + => obj is HandleBase handle && Equals(handle); /// To be consistent with . /// Left part of operator. Can be . /// Right part of operator. Can be . /// if equals to . /// - public static bool operator ==(HandleBase left, HandleBase right) + public static bool operator ==(HandleBase? left, HandleBase? right) => (left is null && right is null) || (!(left is null) && left.Equals(right)); /// To be consistent with . @@ -59,7 +59,7 @@ public override bool Equals(object obj) /// Right part of operator. Can be . /// if is not equal to . /// - public static bool operator !=(HandleBase left, HandleBase right) + public static bool operator !=(HandleBase? left, HandleBase? right) => !(left == right); #endregion diff --git a/K4AdotNet/NativeHandles/HandleWrapper.cs b/K4AdotNet/NativeHandles/HandleWrapper.cs index 3b81eed..034c000 100644 --- a/K4AdotNet/NativeHandles/HandleWrapper.cs +++ b/K4AdotNet/NativeHandles/HandleWrapper.cs @@ -63,7 +63,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Checks that object is not disposed. /// If object is disposed. @@ -93,21 +93,21 @@ public override int GetHashCode() /// Delegates comparison to . /// Another handle to be compared with this one. Can be . /// if both handles reference to one and the same object. - public bool Equals(HandleWrapper other) + public bool Equals(HandleWrapper? other) => !(other is null) && other.Value.Equals(Value); /// Two objects are equal when they reference to one and the same unmanaged object. /// Another handle to be compared with this one. Can be . /// if is and they both reference to one and the same object. - public override bool Equals(object obj) - => obj is HandleWrapper && Equals((HandleWrapper)obj); + public override bool Equals(object? obj) + => obj is HandleWrapper wrapper && Equals(wrapper); /// To be consistent with . /// Left part of operator. Can be . /// Right part of operator. Can be . /// if equals to . /// - public static bool operator ==(HandleWrapper left, HandleWrapper right) + public static bool operator ==(HandleWrapper? left, HandleWrapper? right) => (left is null && right is null) || (!(left is null) && left.Equals(right)); /// To be consistent with . @@ -115,7 +115,7 @@ public override bool Equals(object obj) /// Right part of operator. Can be . /// if is not equal to . /// - public static bool operator !=(HandleWrapper left, HandleWrapper right) + public static bool operator !=(HandleWrapper? left, HandleWrapper? right) => !(left == right); #endregion diff --git a/K4AdotNet/Quaternion.cs b/K4AdotNet/Quaternion.cs index 6785baa..1a6202f 100644 --- a/K4AdotNet/Quaternion.cs +++ b/K4AdotNet/Quaternion.cs @@ -123,7 +123,7 @@ public bool Equals(Quaternion other) /// Object to be compared with this quaternion. /// if is a and is equal to this one. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is null || !(obj is Quaternion)) return false; diff --git a/K4AdotNet/Record/NativeApi.cs b/K4AdotNet/Record/NativeApi.cs index 2886ef6..6ace199 100644 --- a/K4AdotNet/Record/NativeApi.cs +++ b/K4AdotNet/Record/NativeApi.cs @@ -35,7 +35,7 @@ public static extern NativeCallResults.Result RecordCreate( [In] byte[] path, NativeHandles.DeviceHandle device, Sensor.DeviceConfiguration deviceConfiguration, - out NativeHandles.RecordHandle recordingHandle); + out NativeHandles.RecordHandle? recordingHandle); // K4ARECORD_EXPORT k4a_result_t k4a_record_add_tag(k4a_record_t recording_handle, const char *name, const char *value); /// Adds a tag to the recording. @@ -253,7 +253,7 @@ public static extern NativeCallResults.Result RecordWriteCustomTrackData( [DllImport(Sdk.RECORD_DLL_NAME, EntryPoint = "k4a_playback_open", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.Result PlaybackOpen( [In] byte[] path, - out NativeHandles.PlaybackHandle playbackHandle); + out NativeHandles.PlaybackHandle? playbackHandle); // K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_get_raw_calibration(k4a_playback_t playback_handle, // uint8_t* data, @@ -278,7 +278,7 @@ public static extern NativeCallResults.Result PlaybackOpen( [DllImport(Sdk.RECORD_DLL_NAME, EntryPoint = "k4a_playback_get_raw_calibration", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.BufferResult PlaybackGetRawCalibration( NativeHandles.PlaybackHandle playbackHandle, - [Out] byte[] data, + [Out] byte[]? data, ref UIntPtr dataSize); // K4ARECORD_EXPORT k4a_result_t k4a_playback_get_calibration(k4a_playback_t playback_handle, @@ -350,7 +350,7 @@ public static extern byte PlaybackCheckTrackExists( public static extern NativeCallResults.BufferResult PlaybackGetTrackName( NativeHandles.PlaybackHandle playbackHandle, UIntPtr trackIndex, - [Out] byte[] trackName, + [Out] byte[]? trackName, ref UIntPtr trackNameSize); // K4ARECORD_EXPORT bool k4a_playback_track_is_builtin(k4a_playback_t playback_handle, const char* track_name); @@ -407,7 +407,7 @@ public static extern NativeCallResults.Result PlaybackTrackGetVideoSetting( public static extern NativeCallResults.BufferResult PlaybackTrackGetCodecId( NativeHandles.PlaybackHandle playbackHandle, [In] byte[] trackName, - [Out] byte[] codecId, + [Out] byte[]? codecId, ref UIntPtr codecIdSize); // K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_track_get_codec_context(k4a_playback_t playback_handle, @@ -439,7 +439,7 @@ public static extern NativeCallResults.BufferResult PlaybackTrackGetCodecId( public static extern NativeCallResults.BufferResult PlaybackTrackGetCodecContext( NativeHandles.PlaybackHandle playbackHandle, [In] byte[] trackName, - [Out] byte[] codecContext, + [Out] byte[]? codecContext, ref UIntPtr codecContextSize); // K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_get_tag(k4a_playback_t playback_handle, @@ -472,7 +472,7 @@ public static extern NativeCallResults.BufferResult PlaybackTrackGetCodecContext public static extern NativeCallResults.BufferResult PlaybackGetTag( NativeHandles.PlaybackHandle playbackHandle, [In] byte[] name, - [Out] byte[] value, + [Out] byte[]? value, ref UIntPtr valueSize); // K4ARECORD_EXPORT k4a_result_t k4a_playback_set_color_conversion(k4a_playback_t playback_handle, @@ -522,7 +522,7 @@ public static extern NativeCallResults.Result PlaybackSetColorConversion( public static extern NativeCallResults.BufferResult PlaybackGetAttachment( NativeHandles.PlaybackHandle playbackHandle, [In] byte[] fileName, - [Out] byte[] data, + [Out] byte[]? data, ref UIntPtr dataSize); // K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_next_capture(k4a_playback_t playback_handle, @@ -551,7 +551,7 @@ public static extern NativeCallResults.BufferResult PlaybackGetAttachment( [DllImport(Sdk.RECORD_DLL_NAME, EntryPoint = "k4a_playback_get_next_capture", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.StreamResult PlaybackGetNextCapture( NativeHandles.PlaybackHandle playbackHandle, - out NativeHandles.CaptureHandle captureHandle); + out NativeHandles.CaptureHandle? captureHandle); // K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_previous_capture(k4a_playback_t playback_handle, // k4a_capture_t* capture_handle); @@ -579,7 +579,7 @@ public static extern NativeCallResults.StreamResult PlaybackGetNextCapture( [DllImport(Sdk.RECORD_DLL_NAME, EntryPoint = "k4a_playback_get_previous_capture", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.StreamResult PlaybackGetPreviousCapture( NativeHandles.PlaybackHandle playbackHandle, - out NativeHandles.CaptureHandle captureHandle); + out NativeHandles.CaptureHandle? captureHandle); // K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_next_imu_sample(k4a_playback_t playback_handle, // k4a_imu_sample_t* imu_sample); @@ -656,7 +656,7 @@ public static extern NativeCallResults.StreamResult PlaybackGetPreviousImuSample public static extern NativeCallResults.StreamResult PlaybackGetNextDataBlock( NativeHandles.PlaybackHandle playbackHandle, [In] byte[] trackName, - out NativeHandles.PlaybackDataBlockHandle dataHandle); + out NativeHandles.PlaybackDataBlockHandle? dataHandle); // K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_previous_data_block(k4a_playback_t playback_handle, // const char* track_name, @@ -687,7 +687,7 @@ public static extern NativeCallResults.StreamResult PlaybackGetNextDataBlock( public static extern NativeCallResults.StreamResult PlaybackGetPreviousDataBlock( NativeHandles.PlaybackHandle playbackHandle, [In] byte[] trackName, - out NativeHandles.PlaybackDataBlockHandle dataHandle); + out NativeHandles.PlaybackDataBlockHandle? dataHandle); // K4ARECORD_EXPORT uint64_t k4a_playback_data_block_get_device_timestamp_usec(k4a_playback_data_block_t data_block_handle); /// Get the device timestamp of a data block in microseconds. diff --git a/K4AdotNet/Record/Playback.cs b/K4AdotNet/Record/Playback.cs index a1f39f9..671a8c1 100644 --- a/K4AdotNet/Record/Playback.cs +++ b/K4AdotNet/Record/Playback.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; @@ -60,7 +61,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// File system path to recording opened for playback. Not . Not empty. public string FilePath { get; } @@ -142,7 +143,7 @@ public void GetRecordConfiguration(out RecordConfiguration config) /// contains non-ASCII characters. /// This method cannot be called for disposed object. /// - public bool TryGetTag(string name, out string value) + public bool TryGetTag(string name, [NotNullWhen(returnValue: true)] out string? value) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); @@ -161,7 +162,7 @@ public bool TryGetTag(string name, out string value) return true; } - private NativeCallResults.BufferResult GetTag(byte[] name, byte[] value, ref UIntPtr valueSize) + private NativeCallResults.BufferResult GetTag(byte[] name, byte[]? value, ref UIntPtr valueSize) => NativeApi.PlaybackGetTag(handle.ValueNotDisposed, name, value, ref valueSize); /// Reads an attachment file from a recording. @@ -174,7 +175,7 @@ private NativeCallResults.BufferResult GetTag(byte[] name, byte[] value, ref UIn /// is or empty. /// This method cannot be called for disposed object. /// - public bool TryGetAttachment(string attachmentName, out byte[] attachmentData) + public bool TryGetAttachment(string attachmentName, [NotNullWhen(returnValue: true)] out byte[]? attachmentData) { if (string.IsNullOrEmpty(attachmentName)) throw new ArgumentNullException(nameof(attachmentName)); @@ -183,7 +184,7 @@ public bool TryGetAttachment(string attachmentName, out byte[] attachmentData) return Helpers.TryGetValueInByteBuffer(GetAttachment, attachmentNameAsBytes, out attachmentData); } - private NativeCallResults.BufferResult GetAttachment(byte[] attachmentName, byte[] data, ref UIntPtr dataSize) + private NativeCallResults.BufferResult GetAttachment(byte[] attachmentName, byte[]? data, ref UIntPtr dataSize) => NativeApi.PlaybackGetAttachment(handle.ValueNotDisposed, attachmentName, data, ref dataSize); /// @@ -302,7 +303,7 @@ public void SeekTimestamp(Microseconds64 offset, PlaybackSeekOrigin origin) /// /// This method cannot be called for disposed object. /// Error during reading from recording. See logs for details. - public bool TryGetNextCapture(out Sensor.Capture capture) + public bool TryGetNextCapture([NotNullWhen(returnValue: true)] out Sensor.Capture? capture) { var res = NativeApi.PlaybackGetNextCapture(handle.ValueNotDisposed, out var captureHandle); if (res == NativeCallResults.StreamResult.Eof) @@ -341,7 +342,7 @@ public bool TryGetNextCapture(out Sensor.Capture capture) /// /// This method cannot be called for disposed object. /// Error during reading from recording. See logs for details. - public bool TryGetPreviousCapture(out Sensor.Capture capture) + public bool TryGetPreviousCapture([NotNullWhen(returnValue: true)] out Sensor.Capture? capture) { var res = NativeApi.PlaybackGetPreviousCapture(handle.ValueNotDisposed, out var captureHandle); if (res == NativeCallResults.StreamResult.Eof) @@ -419,7 +420,7 @@ private void CheckResult(NativeCallResults.Result result) throw new PlaybackException(FilePath); } - internal static NativeHandles.PlaybackHandle ToHandle(Playback playback) + internal static NativeHandles.PlaybackHandle ToHandle(Playback? playback) => playback?.handle.ValueNotDisposed ?? NativeHandles.PlaybackHandle.Zero; } } diff --git a/K4AdotNet/Record/PlaybackDataBlock.cs b/K4AdotNet/Record/PlaybackDataBlock.cs index 8356d94..c91e173 100644 --- a/K4AdotNet/Record/PlaybackDataBlock.cs +++ b/K4AdotNet/Record/PlaybackDataBlock.cs @@ -35,7 +35,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Gets the device timestamp of a data block in microseconds. /// This property cannot be asked for disposed object. @@ -61,7 +61,7 @@ public IntPtr Buffer /// This method cannot be called for disposed objects. public int CopyTo(byte[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; if (dst.Length < size) @@ -78,7 +78,7 @@ public int CopyTo(byte[] dst) /// This method cannot be called for disposed objects. public int CopyTo(short[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; var elementSize = sizeof(short); @@ -99,7 +99,7 @@ public int CopyTo(short[] dst) /// This method cannot be called for disposed objects. public int CopyTo(float[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; var elementSize = sizeof(float); @@ -120,7 +120,7 @@ public int CopyTo(float[] dst) /// This method cannot be called for disposed objects. public int CopyTo(int[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; var elementSize = sizeof(int); @@ -133,7 +133,7 @@ public int CopyTo(int[] dst) return dstCount; } - internal static PlaybackDataBlock Create(NativeHandles.PlaybackDataBlockHandle handle) + internal static PlaybackDataBlock? Create(NativeHandles.PlaybackDataBlockHandle? handle) => handle != null && !handle.IsInvalid ? new PlaybackDataBlock(handle) : null; } } diff --git a/K4AdotNet/Record/PlaybackTrack.cs b/K4AdotNet/Record/PlaybackTrack.cs index 389fe77..081c825 100644 --- a/K4AdotNet/Record/PlaybackTrack.cs +++ b/K4AdotNet/Record/PlaybackTrack.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace K4AdotNet.Record @@ -26,12 +27,13 @@ internal PlaybackTrack(Playback playback, int index) private string GetTrackName(out byte[] nameAsBytes) { - if (!Helpers.TryGetValueInByteBuffer(GetTrackName, Index, out nameAsBytes)) + if (!Helpers.TryGetValueInByteBuffer(GetTrackName, Index, out var bytes)) throw new PlaybackException("Cannot get name of track #" + Index, playback.FilePath); - return Encoding.UTF8.GetString(nameAsBytes, 0, nameAsBytes.Length - 1); + nameAsBytes = bytes; + return Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1); } - private NativeCallResults.BufferResult GetTrackName(int trackIndex, byte[] trackName, ref UIntPtr trackNameSize) + private NativeCallResults.BufferResult GetTrackName(int trackIndex, byte[]? trackName, ref UIntPtr trackNameSize) => NativeApi.PlaybackGetTrackName(PlaybackHandle, Helpers.Int32ToUIntPtr(trackIndex), trackName, ref trackNameSize); /// Zero-based index of track. @@ -75,7 +77,7 @@ public string CodecId } } - private NativeCallResults.BufferResult GetCodecId(byte[] trackNameAsBytes, byte[] codecId, ref UIntPtr codecIdSize) + private NativeCallResults.BufferResult GetCodecId(byte[] trackNameAsBytes, byte[]? codecId, ref UIntPtr codecIdSize) => NativeApi.PlaybackTrackGetCodecId(PlaybackHandle, trackNameAsBytes, codecId, ref codecIdSize); /// Gets the codec context for this track. @@ -95,7 +97,7 @@ public byte[] CodecContext } } - private NativeCallResults.BufferResult GetCodecContext(byte[] trackNameAsBytes, byte[] codecContext, ref UIntPtr codecContextSize) + private NativeCallResults.BufferResult GetCodecContext(byte[] trackNameAsBytes, byte[]? codecContext, ref UIntPtr codecContextSize) => NativeApi.PlaybackTrackGetCodecContext(PlaybackHandle, trackNameAsBytes, codecContext, ref codecContextSize); /// Reads the next data block for this track. @@ -120,7 +122,7 @@ private NativeCallResults.BufferResult GetCodecContext(byte[] trackNameAsBytes, /// This method cannot be called for disposed playback object. /// Error during reading from recording. See logs for details. /// This method cannot be used with the built-in tracks: "COLOR", "DEPTH", etc... - public bool TryGetNextDataBlock(out PlaybackDataBlock dataBlock) + public bool TryGetNextDataBlock([NotNullWhen(returnValue: true)] out PlaybackDataBlock? dataBlock) { if (IsBuiltIn) throw new InvalidOperationException("This method cannot be called for built-in tracks like COLOR, DEPTH, etc."); @@ -133,9 +135,9 @@ public bool TryGetNextDataBlock(out PlaybackDataBlock dataBlock) return false; } - if (res == NativeCallResults.StreamResult.Succeeded) + if (res == NativeCallResults.StreamResult.Succeeded && dataHandle != null && !dataHandle.IsInvalid) { - dataBlock = PlaybackDataBlock.Create(dataHandle); + dataBlock = PlaybackDataBlock.Create(dataHandle)!; return true; } @@ -164,7 +166,7 @@ public bool TryGetNextDataBlock(out PlaybackDataBlock dataBlock) /// This method cannot be called for disposed playback object. /// Error during reading from recording. See logs for details. /// This method cannot be used with the built-in tracks: "COLOR", "DEPTH", etc... - public bool TryGetPreviousDataBlock(out PlaybackDataBlock dataBlock) + public bool TryGetPreviousDataBlock([NotNullWhen(returnValue: true)] out PlaybackDataBlock? dataBlock) { if (IsBuiltIn) throw new InvalidOperationException("This method cannot be called for built-in tracks like COLOR, DEPTH, etc."); @@ -177,9 +179,9 @@ public bool TryGetPreviousDataBlock(out PlaybackDataBlock dataBlock) return false; } - if (res == NativeCallResults.StreamResult.Succeeded) + if (res == NativeCallResults.StreamResult.Succeeded && dataHandle != null && !dataHandle.IsInvalid) { - dataBlock = PlaybackDataBlock.Create(dataHandle); + dataBlock = PlaybackDataBlock.Create(dataHandle)!; return true; } diff --git a/K4AdotNet/Record/PlaybackTrackCollection.cs b/K4AdotNet/Record/PlaybackTrackCollection.cs index b630686..f172b28 100644 --- a/K4AdotNet/Record/PlaybackTrackCollection.cs +++ b/K4AdotNet/Record/PlaybackTrackCollection.cs @@ -38,7 +38,7 @@ internal PlaybackTrackCollection(Playback playback) /// Information about track with a given name or if there is no track with such name in . /// Appropriate object was disposed. /// - public PlaybackTrack this[string name] + public PlaybackTrack? this[string name] { get { diff --git a/K4AdotNet/Record/Recorder.cs b/K4AdotNet/Record/Recorder.cs index a9c3736..720958b 100644 --- a/K4AdotNet/Record/Recorder.cs +++ b/K4AdotNet/Record/Recorder.cs @@ -72,7 +72,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// File system path to recording. Not . Not empty. public string FilePath { get; } @@ -108,7 +108,7 @@ public void Dispose() public void AddTag(string tagName, string tagValue) { Helpers.CheckTagName(tagName); - if (tagValue == null) + if (tagValue is null) throw new ArgumentNullException(tagValue); var tagNameAsBytes = Helpers.StringToBytes(tagName, Encoding.ASCII); @@ -145,7 +145,7 @@ public void AddAttachment(string attachmentName, byte[] attachmentData) throw new ArgumentNullException(nameof(attachmentName)); if (attachmentName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) throw new ArgumentException($"Invalid value \"{attachmentName}\" of {nameof(attachmentName)}. This name should be a valid filename with an extension.", nameof(attachmentName)); - if (attachmentData == null) + if (attachmentData is null) throw new ArgumentNullException(nameof(attachmentData)); var attachmentNameAsBytes = Helpers.StringToBytes(attachmentName, Encoding.UTF8); @@ -179,7 +179,7 @@ public void WriteHeader() /// This method cannot be called for disposed object. public void WriteCapture(Sensor.Capture capture) { - if (capture == null) + if (capture is null) throw new ArgumentNullException(nameof(capture)); CheckResult(NativeApi.RecordWriteCapture(handle.ValueNotDisposed, Sensor.Capture.ToHandle(capture))); } @@ -215,7 +215,7 @@ private void CheckResult(NativeCallResults.Result result) throw new RecordingException(FilePath); } - internal static NativeHandles.RecordHandle ToHandle(Recorder recorder) + internal static NativeHandles.RecordHandle ToHandle(Recorder? recorder) => recorder?.handle.ValueNotDisposed ?? NativeHandles.RecordHandle.Zero; } } diff --git a/K4AdotNet/Record/RecorderCustomTrack.cs b/K4AdotNet/Record/RecorderCustomTrack.cs index ec6eb55..0925433 100644 --- a/K4AdotNet/Record/RecorderCustomTrack.cs +++ b/K4AdotNet/Record/RecorderCustomTrack.cs @@ -55,7 +55,7 @@ internal RecorderCustomTrack(Recorder recorder, string trackName, byte[] trackNa /// This method cannot be called for disposed . public void WriteData(Microseconds64 deviceTimestamp, byte[] customData) { - if (customData == null) + if (customData is null) throw new ArgumentNullException(nameof(customData)); var customDataLength = Helpers.Int32ToUIntPtr(customData.Length); diff --git a/K4AdotNet/Record/RecorderCustomTrackCollection.cs b/K4AdotNet/Record/RecorderCustomTrackCollection.cs index a603594..3fe7a33 100644 --- a/K4AdotNet/Record/RecorderCustomTrackCollection.cs +++ b/K4AdotNet/Record/RecorderCustomTrackCollection.cs @@ -86,7 +86,7 @@ public RecorderCustomTrack AddVideoTrack(string trackName, string codecId, byte[ throw new ArgumentNullException(nameof(codecId)); if (!codecId.StartsWith("V_")) throw new ArgumentException("Video codec ID should start with 'V_'", nameof(codecId)); - if (codecContext == null) + if (codecContext is null) throw new ArgumentNullException(nameof(codecContext)); if (trackSettings.Width < 0 || trackSettings.Height < 0 || trackSettings.FrameRate < 0) throw new ArgumentException($"Invalid value of {trackSettings}", nameof(trackSettings)); @@ -142,7 +142,7 @@ public RecorderCustomTrack AddCustomSubtitleTrack(string trackName, string codec throw new ArgumentNullException(nameof(codecId)); if (!codecId.StartsWith("S_")) throw new ArgumentException("Subtitle codec ID should start with 'S_'", nameof(codecId)); - if (codecContext == null) + if (codecContext is null) throw new ArgumentNullException(nameof(codecContext)); var trackNameAsBytes = Helpers.StringToBytes(trackName, Encoding.ASCII); diff --git a/K4AdotNet/Sdk.cs b/K4AdotNet/Sdk.cs index ac180ff..1d57a78 100644 --- a/K4AdotNet/Sdk.cs +++ b/K4AdotNet/Sdk.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -76,7 +77,7 @@ public static class Sdk /// Don't use one and the same destination log file for different parts of API (Sensor, Record, Body Tracking). /// Each part uses separate logger instance that do not allowed shared access to the file being written to. /// - public static void ConfigureLogging(TraceLevel level, bool logToStdout = false, string logToFile = null) + public static void ConfigureLogging(TraceLevel level, bool logToStdout = false, string? logToFile = null) { const string PREFIX = "K4A_"; ConfigureLogging(PREFIX, level, logToStdout, logToFile); @@ -96,7 +97,7 @@ public static void ConfigureLogging(TraceLevel level, bool logToStdout = false, /// Don't use one and the same destination log file for different parts of API (Sensor, Record, Body Tracking). /// Each part uses separate logger instance that do not allowed shared access to the file being written to. /// - public static void ConfigureRecordLogging(TraceLevel level, bool logToStdout = false, string logToFile = null) + public static void ConfigureRecordLogging(TraceLevel level, bool logToStdout = false, string? logToFile = null) { const string PREFIX = "K4A_RECORD_"; ConfigureLogging(PREFIX, level, logToStdout, logToFile); @@ -116,13 +117,13 @@ public static void ConfigureRecordLogging(TraceLevel level, bool logToStdout = f /// Don't use one and the same destination log file for different parts of API (Sensor, Record, Body Tracking). /// Each part uses separate logger instance that do not allowed shared access to the file being written to. /// - public static void ConfigureBodyTrackingLogging(TraceLevel level, bool logToStdout = false, string logToFile = null) + public static void ConfigureBodyTrackingLogging(TraceLevel level, bool logToStdout = false, string? logToFile = null) { const string PREFIX = "K4ABT_"; ConfigureLogging(PREFIX, level, logToStdout, logToFile); } - private static void ConfigureLogging(string variableNamePrefix, TraceLevel level, bool logToStdout, string logToFile) + private static void ConfigureLogging(string variableNamePrefix, TraceLevel level, bool logToStdout, string? logToFile) { Environment.SetEnvironmentVariable(variableNamePrefix + "LOG_LEVEL", level.ToSdkLogLevelLetter(), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable(variableNamePrefix + "ENABLE_LOG_TO_STDOUT", logToStdout ? "1" : "0", EnvironmentVariableTarget.Process); @@ -166,13 +167,12 @@ public static readonly string BodyTrackingSdkInstallationGuideUrl /// installation directory of Body Tracking SDK under Program Files. /// /// - public static bool IsBodyTrackingRuntimeAvailable(out string message) + public static bool IsBodyTrackingRuntimeAvailable([NotNullWhen(returnValue: false)] out string? message) { if (!IsOSCompatibleWithBodyTracking(out message)) return false; - var bodyTrackingRuntimePath = GetBodyTrackingRuntimePath(out message); - if (string.IsNullOrEmpty(bodyTrackingRuntimePath)) + if (!TryGetBodyTrackingRuntimePath(out var bodyTrackingRuntimePath, out message)) return false; if (!CheckBodyTrackingRuntimeVersion(bodyTrackingRuntimePath, out message)) @@ -207,7 +207,7 @@ public static bool IsBodyTrackingRuntimeAvailable(out string message) /// /// /// - public static bool TryInitializeBodyTrackingRuntime(out string message) + public static bool TryInitializeBodyTrackingRuntime([NotNullWhen(returnValue: false)] out string? message) { Sensor.Calibration.CreateDummy(Sensor.DepthMode.NarrowView2x2Binned, Sensor.ColorResolution.Off, out var calibration); if (!TryCreateTrackerHandle(ref calibration, BodyTracking.TrackerConfiguration.Default, out var trackerHandle, out message)) @@ -220,7 +220,7 @@ public static bool TryInitializeBodyTrackingRuntime(out string message) return true; } - private static bool CheckBodyTrackingRuntimeVersion(string bodyTrackingRuntimePath, out string message) + private static bool CheckBodyTrackingRuntimeVersion(string bodyTrackingRuntimePath, [NotNullWhen(returnValue: false)] out string? message) { var path = Path.Combine(bodyTrackingRuntimePath, BODY_TRACKING_DLL_NAME + DLL_EXTENSION_WIN); if (File.Exists(path)) @@ -243,7 +243,9 @@ private static bool CheckBodyTrackingRuntimeVersion(string bodyTrackingRuntimePa return false; } - private static string GetBodyTrackingRuntimePath(out string message) + private static bool TryGetBodyTrackingRuntimePath( + [NotNullWhen(returnValue: true)] out string? path, + [NotNullWhen(returnValue: false)] out string? message) { const string BODY_TRACKING_SDK_BIN_PATH = @"Azure Kinect Body Tracking SDK\tools"; @@ -252,14 +254,20 @@ private static string GetBodyTrackingRuntimePath(out string message) // Try current directory var currentDir = Path.GetFullPath(Environment.CurrentDirectory); if (ProbePathForBodyTrackingRuntime(currentDir)) - return currentDir; + { + path = currentDir; + return true; + } // Try base directory of current app domain var baseDir = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory); if (!baseDir.Equals(currentDir, StringComparison.InvariantCultureIgnoreCase)) { if (ProbePathForBodyTrackingRuntime(baseDir)) - return baseDir; + { + path = baseDir; + return true; + } } // Try location of this assembly @@ -269,19 +277,26 @@ private static string GetBodyTrackingRuntimePath(out string message) && !asmDir.Equals(baseDir, StringComparison.InvariantCultureIgnoreCase)) { if (ProbePathForBodyTrackingRuntime(asmDir)) - return asmDir; + { + path = asmDir; + return true; + } } // Try standard location of installed Body Tracking SDK var sdkBinDir = Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), BODY_TRACKING_SDK_BIN_PATH)); if (ProbePathForBodyTrackingRuntime(sdkBinDir)) - return sdkBinDir; + { + path = sdkBinDir; + return true; + } message = $"Cannot find Body Tracking {BODY_TRACKING_EXPECTED_VERSION_MAJOR}.{BODY_TRACKING_EXPECTED_VERSION_MINOR}.x runtime or some of its components (neither in application directory, nor in Body Tracking SDK directory)."; - return null; + path = null; + return false; } - private static bool IsOSCompatibleWithBodyTracking(out string message) + private static bool IsOSCompatibleWithBodyTracking([NotNullWhen(returnValue: false)] out string? message) { if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version < new Version(6, 2) @@ -301,7 +316,7 @@ private static bool IsOSCompatibleWithBodyTracking(out string message) return true; } - private static bool IsCudnnAvailableForBodyTracking(string bodyTrackingRuntimePath, out string message) + private static bool IsCudnnAvailableForBodyTracking(string bodyTrackingRuntimePath, [NotNullWhen(returnValue: false)] out string? message) { if (ProbePathForBodyTrackingRuntime(bodyTrackingRuntimePath)) { @@ -328,14 +343,14 @@ private static bool ProbePathForCudnn(string path) foreach (var dllName in CUDNN_DLL_NAMES) { var fullPath = Path.Combine(path, dllName + DLL_EXTENSION_WIN); - if (!File.Exists(dllName)) + if (!File.Exists(fullPath)) return false; } return true; } - private static string GetCudaBinPath() + private static string? GetCudaBinPath() { const string CUDA_PATH_VARIABLE_NAME = "CUDA_PATH"; const string CUDA_10_0_PATH_VARIABLE_NAME = "CUDA_PATH_V10_0"; @@ -391,7 +406,8 @@ private static bool ProbePathForBodyTrackingRuntime(string path) } internal static bool TryCreateTrackerHandle(ref Sensor.Calibration calibration, BodyTracking.TrackerConfiguration config, - out NativeHandles.TrackerHandle trackerHandle, out string message) + [NotNullWhen(returnValue: true)] out NativeHandles.TrackerHandle? trackerHandle, + [NotNullWhen(returnValue: false)] out string? message) { string runtimePath; @@ -399,8 +415,7 @@ internal static bool TryCreateTrackerHandle(ref Sensor.Calibration calibration, { if (string.IsNullOrEmpty(bodyTrackingRuntimePath)) { - bodyTrackingRuntimePath = GetBodyTrackingRuntimePath(out message); - if (string.IsNullOrEmpty(bodyTrackingRuntimePath)) + if (!TryGetBodyTrackingRuntimePath(out bodyTrackingRuntimePath, out message)) { trackerHandle = null; return false; @@ -439,7 +454,7 @@ internal static bool TryCreateTrackerHandle(ref Sensor.Calibration calibration, return true; } - private static string bodyTrackingRuntimePath; + private static string? bodyTrackingRuntimePath; private static readonly object bodyTrackingRuntimeInitializationSync = new object(); #endregion diff --git a/K4AdotNet/Sensor/Calibration.cs b/K4AdotNet/Sensor/Calibration.cs index b682526..6d9280e 100644 --- a/K4AdotNet/Sensor/Calibration.cs +++ b/K4AdotNet/Sensor/Calibration.cs @@ -33,7 +33,7 @@ public partial struct Calibration /// /// [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = (int)CalibrationGeometry.Count * (int)CalibrationGeometry.Count)] - public CalibrationExtrinsics[] Extrinsics; + public CalibrationExtrinsics[]? Extrinsics; /// Depth camera mode for which calibration was obtained. public DepthMode DepthMode; @@ -68,7 +68,7 @@ public bool IsValid /// /// public CalibrationExtrinsics GetExtrinsics(CalibrationGeometry sourceSensor, CalibrationGeometry targetSensor) - => Extrinsics[(int)sourceSensor * (int)CalibrationGeometry.Count + (int)targetSensor]; + => Extrinsics![(int)sourceSensor * (int)CalibrationGeometry.Count + (int)targetSensor]; /// Helper method to set mutual extrinsics parameters for a given couple of sensors in Azure Kinect device. /// Source coordinate system for transformation. @@ -77,7 +77,7 @@ public CalibrationExtrinsics GetExtrinsics(CalibrationGeometry sourceSensor, Cal /// /// public void SetExtrinsics(CalibrationGeometry sourceSensor, CalibrationGeometry targetSensor, CalibrationExtrinsics extrinsics) - => Extrinsics[(int)sourceSensor * (int)CalibrationGeometry.Count + (int)targetSensor] = extrinsics; + => Extrinsics![(int)sourceSensor * (int)CalibrationGeometry.Count + (int)targetSensor] = extrinsics; #endregion @@ -257,7 +257,7 @@ public static void CreateFromRaw(byte[] rawCalibration, DepthMode depthMode, Col /// public Float2? ConvertColor2DToDepth2D(Float2 sourcePoint2D, Image depthImage) { - if (depthImage == null) + if (depthImage is null) throw new ArgumentNullException(nameof(depthImage)); if (depthImage.IsDisposed) throw new ObjectDisposedException(nameof(depthImage)); diff --git a/K4AdotNet/Sensor/CalibrationIntrinsicParameters.cs b/K4AdotNet/Sensor/CalibrationIntrinsicParameters.cs index 32f77da..a3aaa2f 100644 --- a/K4AdotNet/Sensor/CalibrationIntrinsicParameters.cs +++ b/K4AdotNet/Sensor/CalibrationIntrinsicParameters.cs @@ -116,28 +116,25 @@ public float[] ToArray() /// Index is less than 0 or is greater or equal to . public float this[int index] { - get + get => index switch { - switch (index) - { - case 0: return Cx; - case 1: return Cy; - case 2: return Fx; - case 3: return Fy; - case 4: return K1; - case 5: return K2; - case 6: return K3; - case 7: return K4; - case 8: return K5; - case 9: return K6; - case 10: return Codx; - case 11: return Cody; - case 12: return P2; - case 13: return P1; - case 14: return NotUsed; - default: throw new IndexOutOfRangeException(nameof(index)); - } - } + 0 => Cx, + 1 => Cy, + 2 => Fx, + 3 => Fy, + 4 => K1, + 5 => K2, + 6 => K3, + 7 => K4, + 8 => K5, + 9 => K6, + 10 => Codx, + 11 => Cody, + 12 => P2, + 13 => P1, + 14 => NotUsed, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; set { diff --git a/K4AdotNet/Sensor/Capture.cs b/K4AdotNet/Sensor/Capture.cs index bca3540..c7fca46 100644 --- a/K4AdotNet/Sensor/Capture.cs +++ b/K4AdotNet/Sensor/Capture.cs @@ -49,7 +49,7 @@ private Capture(NativeHandles.CaptureHandle handle) this.handle.Disposed += Handle_Disposed; } - internal static Capture Create(NativeHandles.CaptureHandle handle) + internal static Capture? Create(NativeHandles.CaptureHandle? handle) => handle != null && !handle.IsInvalid ? new Capture(handle) : null; /// @@ -76,7 +76,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Creates new reference to the same unmanaged capture object. /// New object that references exactly to the same underlying unmanaged object as original one. Not . @@ -108,7 +108,7 @@ public Capture DuplicateReference() /// If an existing image is being replaced, the previous image will have the reference released. /// /// This property cannot be called for disposed objects. - public Image ColorImage + public Image? ColorImage { get => children.Register(Image.Create(NativeApi.CaptureGetColorImage(handle.ValueNotDisposed))); set => NativeApi.CaptureSetColorImage(handle.ValueNotDisposed, Image.ToHandle(value)); @@ -136,7 +136,7 @@ public Image ColorImage /// If an existing image is being replaced, the previous image will have the reference released. /// /// This property cannot be called for disposed objects. - public Image DepthImage + public Image? DepthImage { get => children.Register(Image.Create(NativeApi.CaptureGetDepthImage(handle.ValueNotDisposed))); set => NativeApi.CaptureSetDepthImage(handle.ValueNotDisposed, Image.ToHandle(value)); @@ -164,7 +164,7 @@ public Image DepthImage /// If an existing image is being replaced, the previous image will have the reference released. /// /// This property cannot be called for disposed objects. - public Image IRImage + public Image? IRImage { get => children.Register(Image.Create(NativeApi.CaptureGetIRImage(handle.ValueNotDisposed))); set => NativeApi.CaptureSetIRImage(handle.ValueNotDisposed, Image.ToHandle(value)); @@ -185,7 +185,7 @@ public float TemperatureC /// Extracts handle from . /// Managed object. Can be . /// Appropriate unmanaged handle. Can be . - internal static NativeHandles.CaptureHandle ToHandle(Capture capture) + internal static NativeHandles.CaptureHandle ToHandle(Capture? capture) => capture?.handle?.ValueNotDisposed ?? NativeHandles.CaptureHandle.Zero; #region Equatable @@ -193,14 +193,14 @@ internal static NativeHandles.CaptureHandle ToHandle(Capture capture) /// Two captures are equal when they reference to one and the same unmanaged object. /// Another captures to be compared with this one. Can be . /// if both captures reference to one and the same unmanaged object. - public bool Equals(Capture capture) + public bool Equals(Capture? capture) => !(capture is null) && capture.handle.Equals(handle); /// Two captures are equal when they reference to one and the same unmanaged object. /// Some object to be compared with this one. Can be . /// if is also and they both reference to one and the same unmanaged object. - public override bool Equals(object obj) - => obj is Capture && Equals((Capture)obj); + public override bool Equals(object? obj) + => obj is Capture capture && Equals(capture); /// Uses underlying handle as hash code. /// Hash code. Consistent with overridden equality. @@ -213,7 +213,7 @@ public override int GetHashCode() /// Right part of operator. Can be . /// if equals to . /// - public static bool operator ==(Capture left, Capture right) + public static bool operator ==(Capture? left, Capture? right) => (left is null && right is null) || (!(left is null) && left.Equals(right)); /// To be consistent with . @@ -221,7 +221,7 @@ public override int GetHashCode() /// Right part of operator. Can be . /// if is not equal to . /// - public static bool operator !=(Capture left, Capture right) + public static bool operator !=(Capture? left, Capture? right) => !(left == right); /// Convenient (for debugging needs, first of all) string representation of object as an address of unmanaged object in memory. diff --git a/K4AdotNet/Sensor/Device.cs b/K4AdotNet/Sensor/Device.cs index 4867e90..d298843 100644 --- a/K4AdotNet/Sensor/Device.cs +++ b/K4AdotNet/Sensor/Device.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace K4AdotNet.Sensor @@ -49,7 +50,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Zero-based index of this device. /// @@ -191,7 +192,7 @@ public void StopImu() /// This method cannot be called for disposed object. /// Connection with Azure Kinect device has been lost. /// Camera streaming is not running or has been stopped during this call. - public bool TryGetCapture(out Capture capture, Timeout timeout = default) + public bool TryGetCapture([NotNullWhen(returnValue: true)] out Capture? capture, Timeout timeout = default) { var res = NativeApi.DeviceGetCapture(handle.ValueNotDisposed, out var captureHandle, timeout); @@ -226,7 +227,7 @@ public Capture GetCapture() { var res = TryGetCapture(out var capture, Timeout.Infinite); System.Diagnostics.Debug.Assert(res); - return capture; + return capture!; } /// Reads an IMU sample. @@ -384,13 +385,14 @@ public void GetCalibration(DepthMode depthMode, ColorResolution colorResolution, public override string ToString() => "Azure Kinect #" + SerialNumber; - private void CheckResult(NativeCallResults.Result result, string invalidOperationMessage = null) + private void CheckResult(NativeCallResults.Result result, string? invalidOperationMessage = null) { if (result != NativeCallResults.Result.Succeeded) ThrowException(invalidOperationMessage); } - private void ThrowException(string invalidOperationMessage = null) + [DoesNotReturn] + private void ThrowException(string? invalidOperationMessage = null) { handle.CheckNotDisposed(); if (!IsConnected) @@ -415,7 +417,7 @@ private void ThrowException(string invalidOperationMessage = null) /// is less than zero. /// /// - public static bool TryOpen(out Device device, int index = DefaultDeviceIndex) + public static bool TryOpen([NotNullWhen(returnValue: true)] out Device? device, int index = DefaultDeviceIndex) { if (index < 0) throw new ArgumentOutOfRangeException(nameof(index)); @@ -462,7 +464,7 @@ public static Device Open(int index = DefaultDeviceIndex) return device; } - private static bool TryGetSerialNumber(NativeHandles.DeviceHandle deviceHandle, out string serialNumber) + private static bool TryGetSerialNumber(NativeHandles.DeviceHandle deviceHandle, [NotNullWhen(returnValue: true)] out string? serialNumber) { if (!Helpers.TryGetValueInByteBuffer(NativeApi.DeviceGetSerialnum, deviceHandle, out var result)) { @@ -480,7 +482,7 @@ private static bool TryGetSerialNumber(NativeHandles.DeviceHandle deviceHandle, private static bool TryGetHardwareVersion(NativeHandles.DeviceHandle deviceHandle, out HardwareVersion version) => NativeApi.DeviceGetVersion(deviceHandle, out version) == NativeCallResults.Result.Succeeded; - internal static NativeHandles.DeviceHandle ToHandle(Device device) + internal static NativeHandles.DeviceHandle ToHandle(Device? device) => device?.handle.ValueNotDisposed ?? NativeHandles.DeviceHandle.Zero; } } diff --git a/K4AdotNet/Sensor/DeviceConfiguration.cs b/K4AdotNet/Sensor/DeviceConfiguration.cs index 0e62005..41a511e 100644 --- a/K4AdotNet/Sensor/DeviceConfiguration.cs +++ b/K4AdotNet/Sensor/DeviceConfiguration.cs @@ -1,4 +1,5 @@ -using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; namespace K4AdotNet.Sensor { @@ -115,7 +116,7 @@ public struct DeviceConfiguration /// if configuration is valid and can be used in . /// if configuration has some invalid or incompatible parameters. /// - public bool IsValid(out string message) + public bool IsValid([NotNullWhen(returnValue: false)] out string? message) { if (!ColorFormat.IsColor()) { diff --git a/K4AdotNet/Sensor/FirmwareVersion.cs b/K4AdotNet/Sensor/FirmwareVersion.cs index 2c0bd6c..67d1c53 100644 --- a/K4AdotNet/Sensor/FirmwareVersion.cs +++ b/K4AdotNet/Sensor/FirmwareVersion.cs @@ -76,22 +76,20 @@ public bool Equals(FirmwareVersion other) /// Per-component comparison of versions. Implementation of . /// Version to be compared with this one. Can be . /// if versions are the same, - otherwise. - public bool Equals(Version other) + public bool Equals(Version? other) => other != null && Equals(new FirmwareVersion(other)); /// Per-component comparison of versions. /// Object to be compared with this one. /// - if is not and it is version and versions are equal, - otherwise. - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is FirmwareVersion) - return Equals((FirmwareVersion)obj); - if (obj is Version) - return Equals((Version)obj); - return false; - } + public override bool Equals(object? obj) + => obj switch + { + null => false, + FirmwareVersion _ => Equals((FirmwareVersion)obj), + Version _ => Equals((Version)obj), + _ => false + }; /// To be consistent with . /// Left part of operator. @@ -114,7 +112,7 @@ public override bool Equals(object obj) /// Right part of operator. Can be . /// if equals to . /// - public static bool operator ==(FirmwareVersion left, Version right) + public static bool operator ==(FirmwareVersion left, Version? right) => left.Equals(right); /// To be consistent with . @@ -122,7 +120,7 @@ public override bool Equals(object obj) /// Right part of operator. Can be . /// if is not equal to . /// - public static bool operator !=(FirmwareVersion left, Version right) + public static bool operator !=(FirmwareVersion left, Version? right) => !left.Equals(right); /// To be consistent with . @@ -130,7 +128,7 @@ public override bool Equals(object obj) /// Right part of operator. /// if equals to . /// - public static bool operator ==(Version left, FirmwareVersion right) + public static bool operator ==(Version? left, FirmwareVersion right) => right.Equals(left); /// To be consistent with . @@ -138,7 +136,7 @@ public override bool Equals(object obj) /// Right part of operator. /// if is not equal to . /// - public static bool operator !=(Version left, FirmwareVersion right) + public static bool operator !=(Version? left, FirmwareVersion right) => !right.Equals(left); /// Calculates hash code. @@ -171,7 +169,7 @@ public int CompareTo(FirmwareVersion other) /// 0 - equals this one, /// -1 - is less than this one. /// - public int CompareTo(Version other) + public int CompareTo(Version? other) => other is null ? 1 : CompareTo(new FirmwareVersion(other)); /// Versions comparison. Implementation of . @@ -182,16 +180,14 @@ public int CompareTo(Version other) /// -1 - is less than this one. /// /// is not comparable with this one. - public int CompareTo(object obj) - { - if (obj is null) - return 1; - if (obj is FirmwareVersion) - return CompareTo((FirmwareVersion)obj); - if (obj is Version) - return CompareTo((Version)obj); - throw new ArgumentException("Object is not a FirmwareVersion or Version", nameof(obj)); - } + public int CompareTo(object? obj) + => obj switch + { + null => 1, + FirmwareVersion _ => CompareTo((FirmwareVersion)obj), + Version _ => CompareTo((Version)obj), + _ => throw new ArgumentException("Object is not a FirmwareVersion or Version", nameof(obj)) + }; /// Versions comparison. /// Left part of operator. @@ -225,56 +221,56 @@ public int CompareTo(object obj) /// Left part of operator. /// Right part of operator. Can be . /// if is less than . - public static bool operator <(FirmwareVersion left, Version right) + public static bool operator <(FirmwareVersion left, Version? right) => left.CompareTo(right) < 0; /// Versions comparison. /// Left part of operator. /// Right part of operator. Can be . /// if is less than or is equal to . - public static bool operator <=(FirmwareVersion left, Version right) + public static bool operator <=(FirmwareVersion left, Version? right) => left.CompareTo(right) <= 0; /// Versions comparison. /// Left part of operator. /// Right part of operator. Can be . /// if is greater than or is . - public static bool operator >(FirmwareVersion left, Version right) + public static bool operator >(FirmwareVersion left, Version? right) => left.CompareTo(right) > 0; /// Versions comparison. /// Left part of operator. /// Right part of operator. Can be . /// if is greater than or is equal to or is . - public static bool operator >=(FirmwareVersion left, Version right) + public static bool operator >=(FirmwareVersion left, Version? right) => left.CompareTo(right) >= 0; /// Versions comparison. /// Left part of operator. Can be .. /// Right part of operator. /// if is less than or is . - public static bool operator <(Version left, FirmwareVersion right) + public static bool operator <(Version? left, FirmwareVersion right) => right.CompareTo(left) > 0; /// Versions comparison. /// Left part of operator. Can be .. /// Right part of operator. /// if is less than or is equal to or is . - public static bool operator <=(Version left, FirmwareVersion right) + public static bool operator <=(Version? left, FirmwareVersion right) => right.CompareTo(left) >= 0; /// Versions comparison. /// Left part of operator. Can be .. /// Right part of operator. /// if is greater than . - public static bool operator >(Version left, FirmwareVersion right) + public static bool operator >(Version? left, FirmwareVersion right) => right.CompareTo(left) < 0; /// Versions comparison. /// Left part of operator. Can be .. /// Right part of operator. /// if is greater than or is equal to . - public static bool operator >=(Version left, FirmwareVersion right) + public static bool operator >=(Version? left, FirmwareVersion right) => right.CompareTo(left) <= 0; /// String representation of version formatted using the specified format and provider. diff --git a/K4AdotNet/Sensor/Image.cs b/K4AdotNet/Sensor/Image.cs index dd5220e..3d5643d 100644 --- a/K4AdotNet/Sensor/Image.cs +++ b/K4AdotNet/Sensor/Image.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace K4AdotNet.Sensor @@ -21,7 +22,7 @@ private Image(NativeHandles.ImageHandle handle) this.handle.Disposed += Handle_Disposed; } - internal static Image Create(NativeHandles.ImageHandle handle) + internal static Image? Create(NativeHandles.ImageHandle? handle) => handle != null && !handle.IsInvalid ? new Image(handle) : null; /// Creates new image with specified format and size in pixels. @@ -164,7 +165,7 @@ public static Image CreateFromArray(T[] buffer, ImageFormat format, int width public static Image CreateFromArray(T[] buffer, ImageFormat format, int widthPixels, int heightPixels, int strideBytes) where T: struct { - if (buffer == null) + if (buffer is null) throw new ArgumentNullException(nameof(buffer)); if (widthPixels <= 0) throw new ArgumentOutOfRangeException(nameof(widthPixels)); @@ -187,7 +188,7 @@ public static Image CreateFromArray(T[] buffer, ImageFormat format, int width if (res != NativeCallResults.Result.Succeeded || handle == null || handle.IsInvalid) throw new ArgumentException($"Cannot create image with format {format}, size {widthPixels}x{heightPixels} pixels, stride {strideBytes} bytes from buffer of size {sizeBytes} bytes."); - return Create(handle); + return Create(handle)!; } private void Handle_Disposed(object sender, EventArgs e) @@ -217,7 +218,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Creates new reference to the same unmanaged image object. /// New object that references exactly to the same underlying unmanaged object as original one. Not . @@ -336,7 +337,7 @@ public int IsoSpeed /// This method cannot be called for disposed objects. public int CopyTo(byte[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; if (dst.Length < size) @@ -353,7 +354,7 @@ public int CopyTo(byte[] dst) /// This method cannot be called for disposed objects. public int CopyTo(short[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; var elementSize = sizeof(short); @@ -374,7 +375,7 @@ public int CopyTo(short[] dst) /// This method cannot be called for disposed objects. public int CopyTo(float[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; var elementSize = sizeof(float); @@ -395,7 +396,7 @@ public int CopyTo(float[] dst) /// This method cannot be called for disposed objects. public int CopyTo(int[] dst) { - if (dst == null) + if (dst is null) throw new ArgumentNullException(nameof(dst)); var size = SizeBytes; var elementSize = sizeof(int); @@ -415,7 +416,7 @@ public int CopyTo(int[] dst) /// This method cannot be called for disposed objects. public void FillFrom(byte[] src) { - if (src == null) + if (src is null) throw new ArgumentNullException(nameof(src)); if (src.Length != SizeBytes) throw new ArgumentOutOfRangeException(nameof(src) + "." + nameof(src.Length)); @@ -429,7 +430,7 @@ public void FillFrom(byte[] src) /// This method cannot be called for disposed objects. public void FillFrom(short[] src) { - if (src == null) + if (src is null) throw new ArgumentNullException(nameof(src)); var size = SizeBytes; var elementSize = sizeof(short); @@ -447,7 +448,7 @@ public void FillFrom(short[] src) /// This method cannot be called for disposed objects. public void FillFrom(float[] src) { - if (src == null) + if (src is null) throw new ArgumentNullException(nameof(src)); var size = SizeBytes; var elementSize = sizeof(float); @@ -465,7 +466,7 @@ public void FillFrom(float[] src) /// This method cannot be called for disposed objects. public void FillFrom(int[] src) { - if (src == null) + if (src is null) throw new ArgumentNullException(nameof(src)); var size = SizeBytes; var elementSize = sizeof(int); @@ -479,7 +480,7 @@ public void FillFrom(int[] src) /// Extracts handle from . /// Managed object. Can be . /// Appropriate unmanaged handle. Can be . - internal static NativeHandles.ImageHandle ToHandle(Image image) + internal static NativeHandles.ImageHandle ToHandle(Image? image) => image?.handle?.ValueNotDisposed ?? NativeHandles.ImageHandle.Zero; #region Equatable @@ -487,14 +488,14 @@ internal static NativeHandles.ImageHandle ToHandle(Image image) /// Two images are equal when they reference to one and the same unmanaged object. /// Another image to be compared with this one. Can be . /// if both images reference to one and the same unmanaged object. - public bool Equals(Image image) + public bool Equals(Image? image) => !(image is null) && image.handle.Equals(handle); /// Two images are equal when they reference to one and the same unmanaged object. /// Some object to be compared with this one. Can be . /// if is also and they both reference to one and the same unmanaged object. - public override bool Equals(object obj) - => obj is Image && Equals((Image)obj); + public override bool Equals(object? obj) + => obj is Image image && Equals(image); /// Uses underlying handle as hash code. /// Hash code. Consistent with overridden equality. @@ -507,7 +508,7 @@ public override int GetHashCode() /// Right part of operator. Can be . /// if equals to . /// - public static bool operator ==(Image left, Image right) + public static bool operator ==(Image? left, Image? right) => (left is null && right is null) || (!(left is null) && left.Equals(right)); /// To be consistent with . @@ -515,7 +516,7 @@ public override int GetHashCode() /// Right part of operator. Can be . /// if is not equal to . /// - public static bool operator !=(Image left, Image right) + public static bool operator !=(Image? left, Image? right) => !(left == right); /// Convenient (for debugging needs, first of all) string representation of object as an address of unmanaged object in memory. diff --git a/K4AdotNet/Sensor/NativeApi.cs b/K4AdotNet/Sensor/NativeApi.cs index 046af9f..80ac4b0 100644 --- a/K4AdotNet/Sensor/NativeApi.cs +++ b/K4AdotNet/Sensor/NativeApi.cs @@ -22,7 +22,7 @@ internal static class NativeApi /// Output parameter which on success will return a handle to the device. /// if the device was opened successfully. [DllImport(Sdk.SENSOR_DLL_NAME, EntryPoint = "k4a_device_open", CallingConvention = CallingConvention.Cdecl)] - public static extern NativeCallResults.Result DeviceOpen(uint index, out NativeHandles.DeviceHandle deviceHandle); + public static extern NativeCallResults.Result DeviceOpen(uint index, out NativeHandles.DeviceHandle? deviceHandle); // K4A_EXPORT k4a_wait_result_t k4a_device_get_capture(k4a_device_t device_handle, // k4a_capture_t *capture_handle, @@ -48,7 +48,7 @@ internal static class NativeApi [DllImport(Sdk.SENSOR_DLL_NAME, EntryPoint = "k4a_device_get_capture", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.WaitResult DeviceGetCapture( NativeHandles.DeviceHandle deviceHandle, - out NativeHandles.CaptureHandle captureHandle, + out NativeHandles.CaptureHandle? captureHandle, Timeout timeout); // K4A_EXPORT k4a_wait_result_t k4a_device_get_imu_sample(k4a_device_t device_handle, @@ -185,7 +185,7 @@ public static extern NativeCallResults.Result ImageCreate( int widthPixels, int heightPixels, int strideBytes, - out NativeHandles.ImageHandle imageHandle); + out NativeHandles.ImageHandle? imageHandle); // typedef void(k4a_memory_destroy_cb_t)(void *buffer, void *context); /// Callback function for a memory object being destroyed. @@ -230,9 +230,9 @@ public static extern NativeCallResults.Result ImageCreateFromBuffer( int strideBytes, IntPtr buffer, UIntPtr bufferSize, - MemoryDestroyCallback bufferReleaseCallback, + MemoryDestroyCallback? bufferReleaseCallback, IntPtr bufferReleaseCallbackContext, - out NativeHandles.ImageHandle imageHandle); + out NativeHandles.ImageHandle? imageHandle); // K4A_EXPORT uint8_t *k4a_image_get_buffer(k4a_image_t image_handle); /// Get the image buffer. @@ -499,7 +499,7 @@ public static extern NativeCallResults.Result ImageCreateFromBuffer( [DllImport(Sdk.SENSOR_DLL_NAME, EntryPoint = "k4a_device_get_serialnum", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.BufferResult DeviceGetSerialnum( NativeHandles.DeviceHandle deviceHandle, - [Out] byte[] serialNumber, + [Out] byte[]? serialNumber, ref UIntPtr serialNumberSize); // K4A_EXPORT k4a_result_t k4a_device_get_version(k4a_device_t device_handle, k4a_hardware_version_t *version); @@ -621,7 +621,7 @@ public static extern NativeCallResults.Result DeviceSetColorControl( [DllImport(Sdk.SENSOR_DLL_NAME, EntryPoint = "k4a_device_get_raw_calibration", CallingConvention = CallingConvention.Cdecl)] public static extern NativeCallResults.BufferResult DeviceGetRawCalibration( NativeHandles.DeviceHandle deviceHandle, - [Out] byte[] data, + [Out] byte[]? data, ref UIntPtr dataSize); // K4A_EXPORT k4a_result_t k4a_device_get_calibration(k4a_device_t device_handle, diff --git a/K4AdotNet/Sensor/Transformation.cs b/K4AdotNet/Sensor/Transformation.cs index 210617f..dd4c6fd 100644 --- a/K4AdotNet/Sensor/Transformation.cs +++ b/K4AdotNet/Sensor/Transformation.cs @@ -61,7 +61,7 @@ public void Dispose() /// Raised on object disposing (only once). /// - public event EventHandler Disposed; + public event EventHandler? Disposed; /// Depth mode for which this transformation was created. public DepthMode DepthMode { get; } diff --git a/K4AdotNet/Timeout.cs b/K4AdotNet/Timeout.cs index 9e9679e..4f3762b 100644 --- a/K4AdotNet/Timeout.cs +++ b/K4AdotNet/Timeout.cs @@ -111,18 +111,15 @@ public int CompareTo(int otherMs) /// For details see . /// /// is not comparable with this one. - public int CompareTo(object obj) - { - if (obj is null) - return 1; - if (obj is Timeout) - return CompareTo((Timeout)obj); - if (obj is TimeSpan) - return CompareTo((TimeSpan)obj); - if (obj is IConvertible) - return CompareTo(Convert.ToInt32(obj)); - throw new ArgumentException("Object is not a Timeout or TimeSpan or integer number", nameof(obj)); - } + public int CompareTo(object? obj) + => obj switch + { + null => 1, + Timeout timeout => CompareTo(timeout), + TimeSpan span => CompareTo(span), + IConvertible _ => CompareTo(Convert.ToInt32(obj)), + _ => throw new ArgumentException("Object is not a Timeout or TimeSpan or integer number", nameof(obj)) + }; /// String representation of current instance. /// The format to use or for default format. @@ -140,18 +137,15 @@ public string ToString(string format, IFormatProvider formatProvider) /// Overloads to be consistent with . /// Object to be compared with this instance. /// if can be cast to and result is equal to this one. - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is Timeout) - return Equals((Timeout)obj); - if (obj is TimeSpan) - return Equals((TimeSpan)obj); - if (obj is IConvertible) - return Equals(Convert.ToInt32(obj)); - return false; - } + public override bool Equals(object? obj) + => obj switch + { + null => false, + Timeout timeout => Equals(timeout), + TimeSpan span => Equals(span), + IConvertible _ => Equals(Convert.ToInt32(obj)), + _ => false + }; /// Calculates hash code. /// Hash code. Consistent with overridden equality.