Refactor variable initialization for clarity and consistency

Updated variable constructors across the codebase to use explicit names and initial values where applicable. Deprecated old constructor overloads and added new methods and overloads for better flexibility and readability. Minor cleanup includes replacing `default` keywords with `null` and streamlining code syntax.
This commit is contained in:
Sipke Schoorstra 2025-03-13 21:05:28 +01:00
parent d0d3ab1c1c
commit 923e9d335d
No known key found for this signature in database
GPG key ID: 5C10502B28A4268F
31 changed files with 109 additions and 115 deletions

View file

@ -77,6 +77,7 @@
<ItemGroup>
<Folder Include="App_Data\" />
<Folder Include="Etp\" />
</ItemGroup>
</Project>

View file

@ -52,7 +52,7 @@ public abstract class WorkflowBase<TResult> : WorkflowBase
/// <inheritdoc />
protected WorkflowBase()
{
Result = new Variable<TResult>();
Result = new("Result", default!);
}
/// <summary>

View file

@ -10,7 +10,7 @@ namespace Elsa.Workflows.Activities;
public class ParallelForEach : ParallelForEach<object>
{
/// <inheritdoc />
public ParallelForEach([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
public ParallelForEach([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line)
{
}
}

View file

@ -20,7 +20,7 @@ public class ParallelForEach<T> : Activity
private const string CompletedTagsProperty = nameof(CompletedTagsProperty);
/// <inheritdoc />
public ParallelForEach([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
public ParallelForEach([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line)
{
}
@ -34,7 +34,7 @@ public class ParallelForEach<T> : Activity
/// The <see cref="IActivity"/> to execute each iteration.
/// </summary>
[Port]
public IActivity Body { get; set; } = default!;
public IActivity Body { get; set; } = null!;
/// <inheritdoc />
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)

View file

@ -72,9 +72,10 @@ public class WorkflowBuilder(IActivityVisitor activityVisitor, IIdentityGraphSer
}
/// <inheritdoc />
[Obsolete("Use the overload that takes a name instead. This overload will be removed in a future version.")]
public Variable<T> WithVariable<T>()
{
var variable = new Variable<T>();
var variable = new Variable<T>(null!, default!);
Variables.Add(variable);
variable.WithWorkflowStorage();
variable.Id = null!; // This ensures that a deterministic ID is assigned by the builder.
@ -84,13 +85,13 @@ public class WorkflowBuilder(IActivityVisitor activityVisitor, IIdentityGraphSer
/// <inheritdoc />
public Variable<T> WithVariable<T>(string name, T value)
{
var variable = WithVariable<T>();
variable.Name = name;
variable.Value = value;
var variable = new Variable<T>(name, value);
Variables.Add(variable);
return variable;
}
/// <inheritdoc />
[Obsolete("Use the overload that takes a name instead. This overload will be removed in a future version.")]
public Variable<T> WithVariable<T>(T value)
{
var variable = WithVariable<T>();

View file

@ -1,5 +1,7 @@
using System.Text.Json.Serialization;
using Elsa.Expressions.Helpers;
using Elsa.Expressions.Models;
using Humanizer;
namespace Elsa.Workflows.Memory;
@ -11,19 +13,23 @@ public class Variable : MemoryBlockReference
/// <inheritdoc />
public Variable()
{
Id = Guid.NewGuid().ToString("N");
}
/// <inheritdoc />
public Variable(string name) : this()
public Variable(string name)
{
Id = GetIdFromName(name);
Name = name;
}
/// <inheritdoc />
public Variable(string name, object? value = null) : this()
public Variable(string name, object? value = null) : this(name)
{
Value = value;
}
public Variable(string name, object? value = null, string? id = null) : this(name, value)
{
Name = name;
Value = value;
}
@ -45,6 +51,8 @@ public class Variable : MemoryBlockReference
/// <inheritdoc />
public override MemoryBlock Declare() => new(Value, new VariableBlockMetadata(this, StorageDriverType, false));
private string GetIdFromName(string? name) => $"{name?.Camelize() ?? "Unnamed"}{nameof(Variable)}";
}
/// <summary>
@ -59,16 +67,19 @@ public class Variable<T> : Variable
}
/// <inheritdoc />
[Obsolete("Use the constructor that takes a name parameter instead.", true)]
public Variable(T value)
{
Value = value;
}
/// <inheritdoc />
public Variable(string name, T value)
public Variable(string name, T value) : base(name, value)
{
}
public Variable(string name, T value, string? id = null) : base(name, value, id)
{
Name = name;
Value = value;
}
/// <summary>
@ -95,6 +106,18 @@ public class Variable<T> : Variable
Id = id;
return this;
}
public Variable<T> WithName(string name)
{
Name = name;
return this;
}
public Variable<T> WithValue(T value)
{
Value = value;
return this;
}
}
/// <summary>

View file

@ -11,6 +11,6 @@ public class JavaScriptVariablesWorkflow1 : WorkflowBase
{
builder.WithDefinitionId(DefinitionId);
builder.WithVariable("MagicNumber", 3).WithWorkflowStorage();
builder.Root = new RunJavaScript("setMagicNumber(42)", default, default);
builder.Root = new RunJavaScript("setMagicNumber(42)", null, null);
}
}

View file

@ -11,6 +11,6 @@ public class JavaScriptVariablesWorkflow2 : WorkflowBase
{
builder.WithDefinitionId(DefinitionId);
builder.WithVariable("MagicNumber", 3).WithWorkflowStorage();
builder.Root = new RunJavaScript("variables.MagicNumber = 42", default, default);
builder.Root = new RunJavaScript("variables.MagicNumber = 42", null, null);
}
}

View file

@ -11,6 +11,6 @@ public class JavaScriptVariablesWorkflow3 : WorkflowBase
{
builder.WithDefinitionId(DefinitionId);
builder.WithVariable("MagicNumber", 3).WithWorkflowStorage();
builder.Root = new RunJavaScript("setVariable('MagicNumber', 42)", default, default);
builder.Root = new RunJavaScript("setVariable('MagicNumber', 42)", null, null);
}
}

View file

@ -30,7 +30,7 @@ public class JavaScriptVariablesWorkflowTests(App app) : AppComponentTest(app)
var workflowState = workflowInstance!.WorkflowState;
var rootWorkflowActivityExecutionContext = workflowState.ActivityExecutionContexts.Single(x => x.ParentContextId == null);
var variables = GetVariablesDictionary(rootWorkflowActivityExecutionContext);
var magicNumber = variables["Workflow1:variable-1"].ConvertTo<int>();
var magicNumber = variables["magicNumberVariable"].ConvertTo<int>();
Assert.Equal(42, magicNumber);
}

View file

@ -1,3 +1,4 @@
using Elsa.Common.Models;
using Elsa.Expressions.Helpers;
using Elsa.Extensions;
using Elsa.Workflows.ComponentTests.Abstractions;
@ -25,7 +26,7 @@ public class CountdownWorkflowTests(App app) : AppComponentTest(app)
var bookmarkStore = Scope.ServiceProvider.GetRequiredService<IBookmarkStore>();
var runAndCreateRequest = new CreateAndRunWorkflowInstanceRequest
{
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(CountdownWorkflow.DefinitionId),
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(CountdownWorkflow.DefinitionId, VersionOptions.Latest),
};
var runResponse = await workflowClient.CreateAndRunInstanceAsync(runAndCreateRequest);
var workflowInstanceId = runResponse.WorkflowInstanceId;
@ -42,7 +43,7 @@ public class CountdownWorkflowTests(App app) : AppComponentTest(app)
var workflowState = workflowInstance!.WorkflowState;
var rootWorkflowActivityExecutionContext = workflowState.ActivityExecutionContexts.Single(x => x.ParentContextId == null);
var variables = GetVariablesDictionary(rootWorkflowActivityExecutionContext);
var actualCounter = variables["Workflow1:variable-1"].ConvertTo<int>();
var actualCounter = variables["counterVariable"].ConvertTo<int>();
Assert.Equal(--expectedCounter, actualCounter);
var bookmark = bookmarks.Pop();

View file

@ -6,29 +6,29 @@ namespace Elsa.Workflows.ComponentTests.Scenarios.Variables.Workflows;
public class CountdownWorkflow : WorkflowBase
{
public static readonly string DefinitionId = Guid.NewGuid().ToString();
public static readonly string DefinitionId = "Guid.NewGuid().ToString()";
protected override void Build(IWorkflowBuilder builder)
{
builder.WithDefinitionId(DefinitionId);
var counter = builder.WithVariable("Counter", 3).WithWorkflowStorage();
builder.Root = new Sequence
{
Activities =
{
new While(context => counter.Get(context) > 0)
{
Body = new Sequence
{
Activities =
{
new WriteLine(context => $"Counter: {counter.Get(context)}"),
new CountdownStep()
}
}
}
}
};
// var counter = builder.WithVariable("Counter", 3).WithWorkflowStorage();
//
// builder.Root = new Sequence
// {
// Activities =
// {
// new While(context => counter.Get(context) > 0)
// {
// Body = new Sequence
// {
// Activities =
// {
// new WriteLine(context => $"Counter: {counter.Get(context)}"),
// new CountdownStep()
// }
// }
// }
// }
// };
}
}

View file

@ -17,12 +17,8 @@ public class JsonElementConverterTests(ITestOutputHelper testOutputHelper)
public async Task TestJsonObjectPassedAsJsonElement()
{
var javaScriptEvaluator = _serviceProvider.GetRequiredService<IJavaScriptEvaluator>();
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new MemoryRegister());
var jsonVariable = new Variable<object>
{
Name = "JsonVariable"
};
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new());
var jsonVariable = new Variable<object>("JsonVariable", "");
var jsonString = "{\"name\": \"John\", \"age\": 30}";
var jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonString);
@ -36,12 +32,8 @@ public class JsonElementConverterTests(ITestOutputHelper testOutputHelper)
public async Task TestJsonArrayPassedAsJsonElement()
{
var javaScriptEvaluator = _serviceProvider.GetRequiredService<IJavaScriptEvaluator>();
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new MemoryRegister());
var jsonVariable = new Variable<object>
{
Name = "JsonVariable"
};
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new());
var jsonVariable = new Variable<object>("JsonVariable", "");
var jsonString = "[1, 2, 3, 4, 5, 6]";
var jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonString);
@ -55,12 +47,8 @@ public class JsonElementConverterTests(ITestOutputHelper testOutputHelper)
public async Task TestStringPassedAsJsonElement()
{
var javaScriptEvaluator = _serviceProvider.GetRequiredService<IJavaScriptEvaluator>();
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new MemoryRegister());
var jsonVariable = new Variable<object>
{
Name = "JsonVariable"
};
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new());
var jsonVariable = new Variable<object>("JsonVariable", "");
var jsonString = "\"I'm just a string\"";
var jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonString);
@ -74,12 +62,8 @@ public class JsonElementConverterTests(ITestOutputHelper testOutputHelper)
public async Task TestBooleanPassedAsJsonElement()
{
var javaScriptEvaluator = _serviceProvider.GetRequiredService<IJavaScriptEvaluator>();
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new MemoryRegister());
var jsonVariable = new Variable<object>
{
Name = "JsonVariable"
};
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new());
var jsonVariable = new Variable<object>("JsonVariable", "");
var jsonString = "false";
var jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonString);
@ -93,11 +77,8 @@ public class JsonElementConverterTests(ITestOutputHelper testOutputHelper)
public async Task TestNestedJsonPassedAsJsonElement()
{
var javaScriptEvaluator = _serviceProvider.GetRequiredService<IJavaScriptEvaluator>();
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new MemoryRegister());
var jsonVariable = new Variable<object>
{
Name = "JsonVariable"
};
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new());
var jsonVariable = new Variable<object>("JsonVariable", "");
var jsonString = @"
{

View file

@ -31,10 +31,7 @@ public class ToJsonTests(ITestOutputHelper testOutputHelper)
var javaScriptEvaluator = _serviceProvider.GetRequiredService<IJavaScriptEvaluator>();
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, new MemoryRegister());
var unicodeString = UnicodeRangeGenerator.GenerateUnicodeString();
var payloadVariable = new Variable<object>
{
Name = "Payload"
};
var payloadVariable = new Variable<object>("Payload", null!);
var payload = new
{
Text = unicodeString

View file

@ -1,6 +1,5 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Activities.Workflows;
@ -9,7 +8,7 @@ class BreakForEachWorkflow : WorkflowBase
protected override void Build(IWorkflowBuilder workflow)
{
var items = new[] { "C#", "Rust", "Go" };
var currentItem = new Variable<string>();
var currentItem = new Variable<string>("CurrentItem", "");
workflow.Root = new Sequence
{
@ -18,7 +17,7 @@ class BreakForEachWorkflow : WorkflowBase
new WriteLine("Start"),
new ForEach<string>
{
Items = new Input<ICollection<string>>(items),
Items = new(items),
CurrentValue = new (currentItem),
Body = new Sequence
{

View file

@ -7,7 +7,7 @@ class BreakForWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>();
var currentValue = new Variable<int?>("CurrentValue", null);
workflow.Root = new Sequence
{

View file

@ -8,11 +8,7 @@ public class BreakWhileForkWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>
{
Name = "CurrentValue",
Value = 0
};
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.Root = new Sequence
{

View file

@ -7,7 +7,7 @@ public class BreakWhileWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>(0);
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.Root = new Sequence
{

View file

@ -1,6 +1,5 @@
using Elsa.Workflows.Activities;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.IntegrationTests.Activities;
@ -15,10 +14,7 @@ class ForEachWorkflow : WorkflowBase
protected override void Build(IWorkflowBuilder workflow)
{
var currentItem = new Variable<string>
{
Name = "CurrentItem"
};
var currentItem = new Variable<string>("CurrentItem", "");
workflow.Root = new Sequence
{
@ -27,8 +23,8 @@ class ForEachWorkflow : WorkflowBase
{
new ForEach<string>
{
Items = new Input<ICollection<string>>(_items),
CurrentValue = new Output<string?>(currentItem),
Items = new(_items),
CurrentValue = new(currentItem),
Body = new WriteLine(currentItem)
},
}

View file

@ -9,8 +9,8 @@ class NestedForEachWithBreakWorkflow : WorkflowBase
{
var outerItems = new[] { "C#", "Rust", "Go" };
var innerItems = new[] { "Classes", "Functions", "Modules" };
var currentOuterItem = new Variable<string>();
var currentInnerItem = new Variable<string>();
var currentOuterItem = new Variable<string>("CurrentOuterItem", "");
var currentInnerItem = new Variable<string>("CurrentInnerItem", "");
workflow.Root = new ForEach<string>(outerItems)
{

View file

@ -8,8 +8,8 @@ public class SumWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var a = new Variable<int>();
var b = new Variable<int>();
var a = new Variable<int>("A", 0);
var b = new Variable<int>("B", 0);
var sumActivity = new SumActivity(a, b);

View file

@ -8,7 +8,7 @@ public class BreakWhileFromForkWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>(0);
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.WithVariable(currentValue);

View file

@ -8,7 +8,7 @@ public class WaitAllForkWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>(0);
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.WithVariable(currentValue);

View file

@ -8,7 +8,7 @@ public class WaitAnyForkWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var currentValue = new Variable<int?>(0);
var currentValue = new Variable<int?>("CurrentValue", 0);
workflow.WithVariable(currentValue);

View file

@ -13,12 +13,12 @@ public class Sum : Composite<int>
{
private readonly RunJavaScript _runJavaScript;
public Input<int> A { get; set; } = default!;
public Input<int> B { get; set; } = default!;
public Input<int> A { get; set; } = null!;
public Input<int> B { get; set; } = null!;
public Sum()
{
_runJavaScript = new RunJavaScript
_runJavaScript = new()
{
Script = new("getA() + getB();"),
};
@ -42,7 +42,7 @@ public class Sum : Composite<int>
// If the call site set a result variable, assign it to the JavaScript activity's result.
if (Result != null)
_runJavaScript.Result = new Output<object>(Result.MemoryBlockReference)!;
_runJavaScript.Result = new(Result.MemoryBlockReference)!;
}
}
@ -53,11 +53,10 @@ public class SumWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var sum = new Variable<int>();
var sum = workflow.WithVariable<int>("Sum", 0);
workflow.Root = new Sequence
{
Variables = { sum },
Activities =
{
new Sum

View file

@ -12,8 +12,8 @@ public class JavascriptAndLiquidWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
var products = new Variable<object> { Name = "Products", StorageDriverType = typeof(WorkflowInstanceStorageDriver) };
var product = new Variable<object> { Name = "Product", StorageDriverType = typeof(WorkflowInstanceStorageDriver) };
var products = new Variable<object>("Products", null!).WithStorageDriver<WorkflowInstanceStorageDriver>();
var product = new Variable<object>("Product", null!).WithStorageDriver<WorkflowInstanceStorageDriver>();
builder.Root = new Sequence
{

View file

@ -24,13 +24,13 @@ public class ParallelJoinCompletesTests
await _services.PopulateRegistriesAsync();
// Import workflow.
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync($"Scenarios/ImplicitJoins/Workflows/parallel-join.json");
var workflowDefinition = await _services.ImportWorkflowDefinitionAsync("Scenarios/ImplicitJoins/Workflows/parallel-join.json");
// Execute.
var state = await _services.RunWorkflowUntilEndAsync(workflowDefinition.DefinitionId);
// Assert.
var journal = await _services.GetRequiredService<IWorkflowExecutionLogStore>().FindManyAsync(new WorkflowExecutionLogRecordFilter
var journal = await _services.GetRequiredService<IWorkflowExecutionLogStore>().FindManyAsync(new()
{
WorkflowInstanceId = state.Id,
ActivityId = "70fc1183cd5800f2",

View file

@ -8,7 +8,7 @@ class SetGetVariableWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var variable1 = new Variable<string>();
var variable1 = new Variable<string>("Variable1", "");
workflow.Root = new Sequence
{
@ -30,8 +30,8 @@ class SetGetVariablesWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var variable1 = new Variable<string>();
var variable2 = new Variable<string>();
var variable1 = new Variable<string>("Variable1", "");
var variable2 = new Variable<string>("Variable2", "");
workflow.Root = new Sequence
{

View file

@ -8,7 +8,7 @@ class SampleWorkflow : WorkflowBase
{
protected override void Build(IWorkflowBuilder workflow)
{
var variable1 = new Variable<string>();
var variable1 = new Variable<string>("Variable1", "");
workflow.Root = new Sequence
{

View file

@ -23,7 +23,7 @@ public class Tests
{
await _services.PopulateRegistriesAsync();
var expectedValue = "Some value";
var variable1 = new Variable();
var variable1 = new Variable("Variable1");
var workflow = Workflow.FromActivity(new Sequence
{
@ -46,7 +46,7 @@ public class Tests
{
await _services.PopulateRegistriesAsync();
var expectedValue = "Some value";
var variable = new Variable<string>();
var variable = new Variable<string>("Variable", "");
var workflow = Workflow.FromActivity(new Sequence
{

View file

@ -24,7 +24,7 @@ public class Tests
var model = new VariablesContainer(variables);
// Create a typed variable.
var variable = new Variable<bool>();
var variable = new Variable<bool>("Variable", false);
// Add variable to collection.
variables.Add(variable);