diff --git a/ArchiSteamFarm/Collections/FixedSizeConcurrentQueue.cs b/ArchiSteamFarm/Collections/FixedSizeConcurrentQueue.cs index 1881403edf657..a599c0b9c8a06 100644 --- a/ArchiSteamFarm/Collections/FixedSizeConcurrentQueue.cs +++ b/ArchiSteamFarm/Collections/FixedSizeConcurrentQueue.cs @@ -33,19 +33,17 @@ internal sealed class FixedSizeConcurrentQueue : IEnumerable where T : not private readonly ConcurrentQueue BackingQueue = new(); internal byte MaxCount { - get => BackingMaxCount; + get; set { ArgumentOutOfRangeException.ThrowIfZero(value); - BackingMaxCount = value; + field = value; Resize(); } } - private byte BackingMaxCount; - internal FixedSizeConcurrentQueue(byte maxCount) { ArgumentOutOfRangeException.ThrowIfZero(maxCount); diff --git a/ArchiSteamFarm/Core/OS.cs b/ArchiSteamFarm/Core/OS.cs index abdc71112e3f3..c88aea3aa5c07 100644 --- a/ArchiSteamFarm/Core/OS.cs +++ b/ArchiSteamFarm/Core/OS.cs @@ -24,6 +24,7 @@ using System; using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -56,19 +57,18 @@ internal static DateTime ProcessStartTime { internal static string? Runtime => TrimAndNullifyEmptyText(RuntimeInformation.RuntimeIdentifier); + [field: AllowNull] + [field: MaybeNull] internal static string Version { get { - if (!string.IsNullOrEmpty(BackingVersion)) { - return BackingVersion; + if (!string.IsNullOrEmpty(field)) { + return field; } - BackingVersion = $"{Framework ?? "Unknown Framework"}; {Runtime ?? "Unknown Runtime"}; {Description ?? "Unknown OS"}"; - - return BackingVersion; + return field = $"{Framework ?? "Unknown Framework"}; {Runtime ?? "Unknown Runtime"}; {Description ?? "Unknown OS"}"; } } - private static string? BackingVersion; private static Mutex? SingleInstance; internal static void CoreInit(bool minimized, bool systemRequired) { diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index 03277f3f8a182..5e50a560ad3be 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -22,6 +22,7 @@ // limitations under the License. using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using ArchiSteamFarm.Core; @@ -87,10 +88,12 @@ public static class SharedInfo { [PublicAPI] public static bool IsRuntimeTrimmed => BuildInfo.IsRuntimeTrimmed; + [field: AllowNull] + [field: MaybeNull] internal static string HomeDirectory { get { - if (!string.IsNullOrEmpty(CachedHomeDirectory)) { - return CachedHomeDirectory; + if (!string.IsNullOrEmpty(field)) { + return field; } // We're aiming to handle two possible cases here, classic publish and single-file publish which is possible with OS-specific builds @@ -98,9 +101,7 @@ internal static string HomeDirectory { // We can't just return our base directory since it could lead to the (wrong) temporary directory of extracted files in a single-publish scenario // If the path goes to our own binary, the user is using OS-specific build, single-file or not, we'll use path to location of that binary then // Otherwise, this path goes to some third-party binary, likely dotnet/mono, the user is using our generic build or other custom binary, we need to trust our base directory then - CachedHomeDirectory = Path.GetFileNameWithoutExtension(OS.ProcessFileName) == AssemblyName ? Path.GetDirectoryName(OS.ProcessFileName) ?? AppContext.BaseDirectory : AppContext.BaseDirectory; - - return CachedHomeDirectory; + return field = Path.GetFileNameWithoutExtension(OS.ProcessFileName) == AssemblyName ? Path.GetDirectoryName(OS.ProcessFileName) ?? AppContext.BaseDirectory : AppContext.BaseDirectory; } } @@ -109,6 +110,4 @@ internal static string HomeDirectory { internal static Version Version => Assembly.GetExecutingAssembly().GetName().Version ?? throw new InvalidOperationException(nameof(Version)); private static Guid ModuleVersion => Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId; - - private static string? CachedHomeDirectory; } diff --git a/ArchiSteamFarm/Steam/Bot.cs b/ArchiSteamFarm/Steam/Bot.cs index 46c30681ae5ac..901102a8a8b22 100644 --- a/ArchiSteamFarm/Steam/Bot.cs +++ b/ArchiSteamFarm/Steam/Bot.cs @@ -198,13 +198,13 @@ public sealed class Bot : IAsyncDisposable, IDisposable { [JsonIgnore] [PublicAPI] public string? AccessToken { - get => BackingAccessToken; + get; private set { AccessTokenValidUntil = null; if (string.IsNullOrEmpty(value)) { - BackingAccessToken = null; + field = null; return; } @@ -215,7 +215,7 @@ private set { return; } - BackingAccessToken = value; + field = value; if (accessToken.ValidTo > DateTime.MinValue) { AccessTokenValidUntil = accessToken.ValidTo; @@ -289,7 +289,6 @@ private set { private DateTime? AccessTokenValidUntil; private string? AuthCode; - private string? BackingAccessToken; private CancellationTokenSource? CallbacksAborted; private Timer? ConnectionFailureTimer; private bool FirstTradeSent; diff --git a/ArchiSteamFarm/Steam/Data/InventoryResponse.cs b/ArchiSteamFarm/Steam/Data/InventoryResponse.cs index 0d6447b6c51a7..7e035cfb2458b 100644 --- a/ArchiSteamFarm/Steam/Data/InventoryResponse.cs +++ b/ArchiSteamFarm/Steam/Data/InventoryResponse.cs @@ -34,17 +34,15 @@ namespace ArchiSteamFarm.Steam.Data; internal sealed class InventoryResponse : OptionalResultResponse { internal EResult? ErrorCode { get { - if (CachedErrorCode.HasValue) { - return CachedErrorCode; + if (field.HasValue) { + return field; } if (string.IsNullOrEmpty(ErrorText)) { return null; } - CachedErrorCode = SteamUtilities.InterpretError(ErrorText); - - return CachedErrorCode; + return field = SteamUtilities.InterpretError(ErrorText); } } @@ -76,8 +74,6 @@ internal EResult? ErrorCode { [JsonPropertyName("total_inventory_count")] internal uint TotalInventoryCount { get; private init; } - private EResult? CachedErrorCode; - [JsonConstructor] private InventoryResponse() { } } diff --git a/ArchiSteamFarm/Steam/Storage/BotConfig.cs b/ArchiSteamFarm/Steam/Storage/BotConfig.cs index 0d1c3ee461999..b87497067a840 100644 --- a/ArchiSteamFarm/Steam/Storage/BotConfig.cs +++ b/ArchiSteamFarm/Steam/Storage/BotConfig.cs @@ -210,13 +210,13 @@ public sealed class BotConfig { [JsonInclude] public string? SteamLogin { - get => BackingSteamLogin; + get; internal set { IsSteamLoginSet = true; - BackingSteamLogin = value; + field = value; } - } + } = DefaultSteamLogin; [JsonInclude] [SwaggerSteamIdentifier(AccountType = EAccountType.Clan)] @@ -229,24 +229,24 @@ internal set { [SwaggerValidValues(ValidStringValues = ["0"])] [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "This is optional, supportive attribute, we don't care if it gets trimmed or not")] public string? SteamParentalCode { - get => BackingSteamParentalCode; + get; internal set { IsSteamParentalCodeSet = true; - BackingSteamParentalCode = value; + field = value; } - } + } = DefaultSteamParentalCode; [JsonInclude] [SwaggerSecurityCritical] public string? SteamPassword { - get => BackingSteamPassword; + get; internal set { IsSteamPasswordSet = true; - BackingSteamPassword = value; + field = value; } - } + } = DefaultSteamPassword; [JsonInclude] [MaxLength(SteamTradeTokenLength)] @@ -284,10 +284,6 @@ internal set { internal bool IsSteamPasswordSet { get; set; } internal bool Saving { get; set; } - private string? BackingSteamLogin = DefaultSteamLogin; - private string? BackingSteamParentalCode = DefaultSteamParentalCode; - private string? BackingSteamPassword = DefaultSteamPassword; - [JsonDisallowNull] [JsonInclude] [JsonPropertyName($"{SharedInfo.UlongCompatibilityStringPrefix}{nameof(SteamMasterClanID)}")] diff --git a/ArchiSteamFarm/Storage/GlobalConfig.cs b/ArchiSteamFarm/Storage/GlobalConfig.cs index cdee09b868e4a..560117e2c1275 100644 --- a/ArchiSteamFarm/Storage/GlobalConfig.cs +++ b/ArchiSteamFarm/Storage/GlobalConfig.cs @@ -154,8 +154,8 @@ public sealed class GlobalConfig { [PublicAPI] public WebProxy? WebProxy { get { - if (BackingWebProxy != null) { - return BackingWebProxy; + if (field != null) { + return field; } if (string.IsNullOrEmpty(WebProxyText)) { @@ -191,9 +191,7 @@ public WebProxy? WebProxy { proxy.Credentials = credentials; } - BackingWebProxy = proxy; - - return proxy; + return field = proxy; } } @@ -253,13 +251,13 @@ public WebProxy? WebProxy { [JsonInclude] [SwaggerSecurityCritical] public string? IPCPassword { - get => BackingIPCPassword; + get; internal set { IsIPCPasswordSet = true; - BackingIPCPassword = value; + field = value; } - } + } = DefaultIPCPassword; [JsonInclude] public ArchiCryptoHelper.EHashingMethod IPCPasswordFormat { get; private init; } = DefaultIPCPasswordFormat; @@ -268,13 +266,13 @@ internal set { [JsonInclude] [SwaggerSecurityCritical] public Guid? LicenseID { - get => BackingLicenseID; + get; internal set { IsLicenseIDSet = true; - BackingLicenseID = value; + field = value; } - } + } = DefaultLicenseID; [JsonInclude] [Range(byte.MinValue, byte.MaxValue)] @@ -349,18 +347,13 @@ internal set { [JsonInclude] [SwaggerSecurityCritical] internal string? WebProxyPassword { - get => BackingWebProxyPassword; + get; set { IsWebProxyPasswordSet = true; - BackingWebProxyPassword = value; + field = value; } - } - - private string? BackingIPCPassword = DefaultIPCPassword; - private Guid? BackingLicenseID = DefaultLicenseID; - private WebProxy? BackingWebProxy; - private string? BackingWebProxyPassword = DefaultWebProxyPassword; + } = DefaultWebProxyPassword; [JsonDisallowNull] [JsonInclude] diff --git a/ArchiSteamFarm/Web/GitHub/Data/ReleaseResponse.cs b/ArchiSteamFarm/Web/GitHub/Data/ReleaseResponse.cs index 806882f05d893..1c2cbb821b5b1 100644 --- a/ArchiSteamFarm/Web/GitHub/Data/ReleaseResponse.cs +++ b/ArchiSteamFarm/Web/GitHub/Data/ReleaseResponse.cs @@ -39,8 +39,8 @@ namespace ArchiSteamFarm.Web.GitHub.Data; public sealed class ReleaseResponse { internal string? ChangelogHTML { get { - if (BackingChangelogHTML != null) { - return BackingChangelogHTML; + if (field != null) { + return field; } if (Changelog == null) { @@ -56,14 +56,14 @@ internal string? ChangelogHTML { renderer.Render(Changelog); writer.Flush(); - return BackingChangelogHTML = writer.ToString(); + return field = writer.ToString(); } } internal string? ChangelogPlainText { get { - if (BackingChangelogPlainText != null) { - return BackingChangelogPlainText; + if (field != null) { + return field; } if (Changelog == null) { @@ -83,14 +83,14 @@ internal string? ChangelogPlainText { renderer.Render(Changelog); writer.Flush(); - return BackingChangelogPlainText = writer.ToString(); + return field = writer.ToString(); } } private MarkdownDocument? Changelog { get { - if (BackingChangelog != null) { - return BackingChangelog; + if (field != null) { + return field; } if (string.IsNullOrEmpty(MarkdownBody)) { @@ -99,7 +99,7 @@ private MarkdownDocument? Changelog { return null; } - return BackingChangelog = ExtractChangelogFromBody(MarkdownBody); + return field = ExtractChangelogFromBody(MarkdownBody); } } @@ -128,10 +128,6 @@ private MarkdownDocument? Changelog { [JsonRequired] public string Tag { get; private init; } = ""; - private MarkdownDocument? BackingChangelog; - private string? BackingChangelogHTML; - private string? BackingChangelogPlainText; - [JsonConstructor] private ReleaseResponse() { } diff --git a/Directory.Build.props b/Directory.Build.props index a34be44bace42..1be7211c4cb3a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ ASF is a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously. true none - latest + preview true en CA1028,CA1031,CS1591