diff --git a/src/ConfigCatClient/Evaluation/EvaluateContext.cs b/src/ConfigCatClient/Evaluation/EvaluateContext.cs index 5ec5d16b..4899f00d 100644 --- a/src/ConfigCatClient/Evaluation/EvaluateContext.cs +++ b/src/ConfigCatClient/Evaluation/EvaluateContext.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using ConfigCat.Client.Utils; namespace ConfigCat.Client.Evaluation; @@ -7,11 +8,15 @@ internal struct EvaluateContext { public readonly string Key; public readonly Setting Setting; - public readonly User? User; public readonly IReadOnlyDictionary Settings; + private readonly User? user; + + [MemberNotNullWhen(true, nameof(UserAttributes))] + public readonly bool IsUserAvailable => this.user is not null; + private IReadOnlyDictionary? userAttributes; - public IReadOnlyDictionary? UserAttributes => this.userAttributes ??= this.User?.GetAllAttributes(); + public IReadOnlyDictionary? UserAttributes => this.userAttributes ??= this.user?.GetAllAttributes(); private List? visitedFlags; public List VisitedFlags => this.visitedFlags ??= new List(); @@ -25,7 +30,7 @@ public EvaluateContext(string key, Setting setting, User? user, IReadOnlyDiction { this.Key = key; this.Setting = setting; - this.User = user; + this.user = user; this.Settings = settings; this.userAttributes = null; @@ -35,9 +40,9 @@ public EvaluateContext(string key, Setting setting, User? user, IReadOnlyDiction } public EvaluateContext(string key, Setting setting, ref EvaluateContext dependentFlagContext) - : this(key, setting, dependentFlagContext.User, dependentFlagContext.Settings) + : this(key, setting, dependentFlagContext.user, dependentFlagContext.Settings) { - this.userAttributes = dependentFlagContext.userAttributes; + this.userAttributes = dependentFlagContext.UserAttributes; this.visitedFlags = dependentFlagContext.VisitedFlags; // crucial to use the property here to make sure the list is created! this.LogBuilder = dependentFlagContext.LogBuilder; } diff --git a/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs b/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs index 60e0d233..8784fdba 100644 --- a/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs +++ b/src/ConfigCatClient/Evaluation/RolloutEvaluator.cs @@ -35,7 +35,7 @@ public EvaluateResult Evaluate(T defaultValue, ref EvaluateContext context, [ logBuilder.Append($"Evaluating '{context.Key}'"); - if (context.User is not null) + if (context.IsUserAvailable) { logBuilder.Append($" for User '{context.UserAttributes.Serialize()}'"); } @@ -173,7 +173,7 @@ private bool TryEvaluatePercentageOptions(PercentageOption[] percentageOptions, { var logBuilder = context.LogBuilder; - if (context.User is null) + if (!context.IsUserAvailable) { logBuilder?.NewLine("Skipping % options because the User Object is missing."); @@ -187,14 +187,9 @@ private bool TryEvaluatePercentageOptions(PercentageOption[] percentageOptions, return false; } - string? percentageOptionsAttributeValue; - var percentageOptionsAttributeName = context.Setting.PercentageOptionsAttribute; - if (percentageOptionsAttributeName is null) - { - percentageOptionsAttributeName = nameof(User.Identifier); - percentageOptionsAttributeValue = context.User.Identifier; - } - else if (!context.UserAttributes!.TryGetValue(percentageOptionsAttributeName, out percentageOptionsAttributeValue)) + var percentageOptionsAttributeName = context.Setting.PercentageOptionsAttribute ?? nameof(User.Identifier); + + if (!context.UserAttributes.TryGetValue(percentageOptionsAttributeName, out var percentageOptionsAttributeValue)) { logBuilder?.NewLine().Append($"Skipping % options because the User.{percentageOptionsAttributeName} attribute is missing."); @@ -334,7 +329,7 @@ private bool EvaluateUserCondition(UserCondition condition, string contextSalt, var logBuilder = context.LogBuilder; logBuilder?.AppendUserCondition(condition); - if (context.User is null) + if (!context.IsUserAvailable) { if (!context.IsMissingUserObjectLogged) { @@ -348,7 +343,7 @@ private bool EvaluateUserCondition(UserCondition condition, string contextSalt, var userAttributeName = condition.ComparisonAttribute ?? throw new InvalidOperationException("Comparison attribute name is missing."); - if (!(context.UserAttributes!.TryGetValue(userAttributeName, out var userAttributeValue) && userAttributeValue.Length > 0)) + if (!(context.UserAttributes.TryGetValue(userAttributeName, out var userAttributeValue) && userAttributeValue.Length > 0)) { this.logger.UserObjectAttributeIsMissing(condition.ToString(), context.Key, userAttributeName); error = string.Format(CultureInfo.InvariantCulture, MissingUserAttributeError, userAttributeName); @@ -783,7 +778,7 @@ private bool EvaluateSegmentCondition(SegmentCondition condition, ref EvaluateCo var logBuilder = context.LogBuilder; logBuilder?.AppendSegmentCondition(condition); - if (context.User is null) + if (!context.IsUserAvailable) { if (!context.IsMissingUserObjectLogged) {