Skip to content

Commit 6f71ff4

Browse files
committed
Fix CS0169 and Could not load file or assembly Microsoft.Bcl.AsyncInterfaces
1 parent c2bde2d commit 6f71ff4

4 files changed

Lines changed: 60 additions & 22 deletions

File tree

samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<PackageReference Include="System.IO.Hashing" Version="$(SihVersion)" />
2727
</ItemGroup>
2828
<ItemGroup>
29+
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.1" />
2930
<PackageReference Include="System.Drawing.Common" Version="10.0.1" />
3031
<!-- The Test SDK is required only for the VSTest Adapter to work -->
3132
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />

src/BenchmarkDotNet/Code/CodeGenerator.cs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ internal static string Generate(BuildPartition buildPartition, CodeGenBenchmarkR
3232
{
3333
var benchmark = buildInfo.BenchmarkCase;
3434

35-
string benchmarkTypeCode = GetDeclarationsProvider(benchmark)
35+
var declarationsProvider = GetDeclarationsProvider(benchmark);
36+
var extraFields = declarationsProvider.GetExtraFields();
37+
38+
string benchmarkTypeCode = declarationsProvider
3639
.ReplaceTemplate(new SmartStringBuilder(ResourceHelper.LoadTemplate("BenchmarkType.txt")))
3740
.Replace("$ID$", buildInfo.Id.ToString())
3841
.Replace("$JobSetDefinition$", GetJobsSetDefinition(benchmark))
3942
.Replace("$ParamsContent$", GetParamsContent(benchmark))
4043
.Replace("$ArgumentsDefinition$", GetArgumentsDefinition(benchmark))
41-
.Replace("$DeclareArgumentFields$", GetDeclareArgumentFields(benchmark))
44+
.Replace("$DeclareFieldsContainer$", GetDeclareFieldsContainer(benchmark, buildInfo.Id, extraFields))
4245
.Replace("$InitializeArgumentFields$", GetInitializeArgumentFields(benchmark))
4346
.Replace("$EngineFactoryType$", GetEngineFactoryTypeName(benchmark))
4447
.Replace("$RunExtraIteration$", buildInfo.Config.HasExtraIterationDiagnoser(benchmark) ? "true" : "false")
@@ -144,11 +147,48 @@ private static string GetArgumentsDefinition(BenchmarkCase benchmarkCase)
144147
benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
145148
.Select((parameter, index) => $"{GetParameterModifier(parameter)} {parameter.ParameterType.GetCorrectCSharpTypeName()} arg{index}"));
146149

147-
private static string GetDeclareArgumentFields(BenchmarkCase benchmarkCase)
148-
=> string.Join(
149-
Environment.NewLine,
150-
benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
151-
.Select((parameter, index) => $"public {GetFieldType(parameter.ParameterType, benchmarkCase.Parameters.GetArgument(parameter.Name!)).GetCorrectCSharpTypeName()} __argField{index};"));
150+
private static string GetDeclareFieldsContainer(BenchmarkCase benchmarkCase, BenchmarkId benchmarkId, string[] extraFields)
151+
{
152+
var fields = benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
153+
.Select((parameter, index) => $"public {GetFieldType(parameter.ParameterType, benchmarkCase.Parameters.GetArgument(parameter.Name!)).GetCorrectCSharpTypeName()} __argField{index};")
154+
.Concat(extraFields)
155+
.ToArray();
156+
157+
// Prevent CS0169
158+
if (fields.Length == 0)
159+
{
160+
return string.Empty;
161+
}
162+
163+
// Wrapper struct is necessary because of error CS4004: Cannot await in an unsafe context
164+
var sb = new StringBuilder();
165+
sb.AppendLine("""
166+
[global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Auto)]
167+
private unsafe struct FieldsContainer
168+
{
169+
""");
170+
foreach (var field in fields)
171+
{
172+
sb.AppendLine($" {field}");
173+
}
174+
sb.AppendLine(" }");
175+
sb.AppendLine();
176+
sb.AppendLine($" private global::BenchmarkDotNet.Autogenerated.Runnable_{benchmarkId.Value}.FieldsContainer __fieldsContainer;");
177+
return sb.ToString();
178+
}
179+
180+
/*
181+
182+
[global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Auto)]
183+
private unsafe struct FieldsContainer
184+
{
185+
$DeclareArgumentFields$
186+
$ExtraFields$
187+
}
188+
189+
private global::BenchmarkDotNet.Autogenerated.Runnable_$ID$.FieldsContainer __fieldsContainer;
190+
191+
*/
152192

153193
private static string GetInitializeArgumentFields(BenchmarkCase benchmarkCase)
154194
=> string.Join(

src/BenchmarkDotNet/Code/DeclarationsProvider.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ internal abstract class DeclarationsProvider(BenchmarkCase benchmark)
2626
protected BenchmarkCase Benchmark { get; } = benchmark;
2727
protected Descriptor Descriptor => Benchmark.Descriptor;
2828

29+
public abstract string[] GetExtraFields();
30+
2931
public SmartStringBuilder ReplaceTemplate(SmartStringBuilder smartStringBuilder)
3032
{
3133
Replace(smartStringBuilder, Descriptor.GlobalSetupMethod, "$GlobalSetupModifiers$", "$GlobalSetupImpl$", false);
@@ -98,6 +100,8 @@ protected string GetPassArgumentsDirect()
98100

99101
internal class SyncDeclarationsProvider(BenchmarkCase benchmark) : DeclarationsProvider(benchmark)
100102
{
103+
public override string[] GetExtraFields() => [];
104+
101105
protected override string PrependExtraGlobalCleanupImpl(string impl) => impl;
102106

103107
protected override SmartStringBuilder ReplaceCore(SmartStringBuilder smartStringBuilder)
@@ -152,7 +156,6 @@ protected override SmartStringBuilder ReplaceCore(SmartStringBuilder smartString
152156
""";
153157

154158
return smartStringBuilder
155-
.Replace("$ExtraFields$", string.Empty)
156159
.Replace("$CoreImpl$", coreImpl);
157160
}
158161

@@ -177,6 +180,13 @@ private string GetPassArguments()
177180

178181
internal class AsyncDeclarationsProvider(BenchmarkCase benchmark) : DeclarationsProvider(benchmark)
179182
{
183+
public override string[] GetExtraFields() =>
184+
[
185+
$"public {typeof(WorkloadContinuerAndValueTaskSource).GetCorrectCSharpTypeName()} workloadContinuerAndValueTaskSource;",
186+
$"public {typeof(IClock).GetCorrectCSharpTypeName()} clock;",
187+
"public long invokeCount;"
188+
];
189+
180190
protected override string PrependExtraGlobalCleanupImpl(string impl)
181191
=> $"""
182192
this.__fieldsContainer.workloadContinuerAndValueTaskSource?.Complete();
@@ -263,11 +273,6 @@ private async void __StartWorkload()
263273
""";
264274

265275
return smartStringBuilder
266-
.Replace("$ExtraFields$", $"""
267-
public {typeof(WorkloadContinuerAndValueTaskSource).GetCorrectCSharpTypeName()} workloadContinuerAndValueTaskSource;
268-
public global::Perfolizer.Horology.IClock clock;
269-
public long invokeCount;
270-
""")
271276
.Replace("$CoreImpl$", coreImpl);
272277
}
273278

src/BenchmarkDotNet/Templates/BenchmarkType.txt

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,7 @@
6868
$ParamsContent$
6969
}
7070

71-
// Necessary because of error CS4004: Cannot await in an unsafe context
72-
[global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Auto)]
73-
private unsafe struct FieldsContainer
74-
{
75-
$DeclareArgumentFields$
76-
$ExtraFields$
77-
}
78-
79-
private global::BenchmarkDotNet.Autogenerated.Runnable_$ID$.FieldsContainer __fieldsContainer;
71+
$DeclareFieldsContainer$
8072

8173
private $GlobalSetupModifiers$ global::System.Threading.Tasks.ValueTask __GlobalSetup()
8274
{

0 commit comments

Comments
 (0)