- TargetFrameworks net48;net40. net48 keeps x64 + ViGEm + System.IO.Ports
package; net40 adds Microsoft.Bcl.Async + System.ValueTuple and uses the
in-box SerialPort.
- Compat/TaskCompat bridges Task.Run/Delay/WhenAny/WhenAll (TaskEx on
net40) and SemaphoreSlim.WaitAsync (net40 blocks briefly - trivial at
9600 baud).
- IReadOnlyList/IReadOnlyDictionary -> IList/IDictionary throughout
(net40 predates the IReadOnly* interfaces and the Bcl backport cannot
make arrays implement them).
- HashCode.Combine replaced with a manual combine (Bcl.HashCode has no
net40 build); Marshal.SizeOf<T> -> typeof form; ViGEmJoystickSink
gated #if !NET40. HidFeederJoystickSink stays on both flavors - it
will drive RioGamepadXP.sys on XP via the same contract.
Both TFMs build; 275 tests green on net48.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Retargets RioJoy.Core/Overlay/Tray + tests from net8.0-windows to net48 so
the app can be tested as a framework-dependent build (relies on the in-box
.NET Framework 4.8 on Windows 10/11). Builds clean; all 241 tests pass.
Polyfills (no behavior change):
- PolySharp source generator for init/records/Index/Range/required members.
- System.Memory, System.Text.Json, Microsoft.Bcl.HashCode,
System.Threading.Channels (tests) NuGet packages.
- Compat/Net48Polyfills.cs: GetValueOrDefault, KeyValuePair.Deconstruct,
Math.Clamp; tests/TestPolyfills.cs: Task.WaitAsync.
Source adjustments for APIs absent on net48:
- ArgumentNullException/ArgumentException.ThrowIf* inlined to manual guards.
- Convert.ToHexString, Encoding.Latin1, Environment.ProcessPath,
ApplicationConfiguration.Initialize, Enum.GetNames<T>/GetValues<T>,
string.StartsWith(char), string.Split(char, opts), TextBox.PlaceholderText,
PeriodicTimer, Memory-based Stream Read/WriteAsync, array range-slicing.
- Dropped [SupportedOSPlatform] hints (net48 is single-platform).
deploy/build-package.ps1: publish framework-dependent (no self-contained).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>