напиши код по данному алгоритму “Эксперимент 1. Создание массива
В файле ArrayCreationTasks.cs есть две реализации уже знакомого вам интерфейса ITask для работы с классом Benchmark. Оба класса создают массив в методе Run. Но один делает массив структур, а второй массив классов."using System;
using System.Runtime.CompilerServices;

namespace StructBenchmarking;

public class StructArrayCreationTask : ITask
{
	private readonly int size;
	private object array;

	public StructArrayCreationTask(int size)
	{
		this.size = size;
	}
	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	public void Run()
	{
		switch (size)
		{
			case 16:
				array = new S16[Constants.ArraySize];
				break;
			case 32:
				array = new S32[Constants.ArraySize];
				break;
			case 64:
				array = new S64[Constants.ArraySize];
				break;
			case 128:
				array = new S128[Constants.ArraySize];
				break;
			case 256:
				array = new S256[Constants.ArraySize];
				break;
			case 512:
				array = new S512[Constants.ArraySize];
				break;
			default:
				throw new ArgumentException();
		}
	}
}


public class ClassArrayCreationTask : ITask
{
	private readonly int size;
	public C16[] c16;
	public C32[] c32;
	public C64[] c64;
	public C128[] c128;
	public C256[] c256;
	public C512[] c512;

	public ClassArrayCreationTask(int size)
	{
		this.size = size;
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	public void Run()
	{
		switch (size)
		{
			case 16:
				c16 = new C16[Constants.ArraySize];
				for (int i = 0; i < Constants.ArraySize; i++) c16[i] = new C16();
				break;
			case 32:
				c32 = new C32[Constants.ArraySize];
				for (int i = 0; i < Constants.ArraySize; i++) c32[i] = new C32();
				break;
			case 64:
				c64 = new C64[Constants.ArraySize];
				for (int i = 0; i < Constants.ArraySize; i++) c64[i] = new C64();
				break;
			case 128:
				c128 = new C128[Constants.ArraySize];
				for (int i = 0; i < Constants.ArraySize; i++) c128[i] = new C128();
				break;
			case 256:
				c256 = new C256[Constants.ArraySize];
				for (int i = 0; i < Constants.ArraySize; i++) c256[i] = new C256();
				break;
			case 512:
				c512 = new C512[Constants.ArraySize];
				for (int i = 0; i < Constants.ArraySize; i++) c512[i] = new C512();
				break;
			default:
				throw new ArgumentException();
		}
	}
}"

"using System.Collections.Generic;

namespace StructBenchmarking;

public class Experiments
{
	public static ChartData BuildChartDataForArrayCreation(
		IBenchmark benchmark, int repetitionsCount)
	{
		var classesTimes = new List<ExperimentResult>();
		var structuresTimes = new List<ExperimentResult>();
            
		//...

		return new ChartData
		{
			Title = "Create array",
			ClassPoints = classesTimes,
			StructPoints = structuresTimes,
		};
	}

	public static ChartData BuildChartDataForMethodCall(
		IBenchmark benchmark, int repetitionsCount)
	{
		var classesTimes = new List<ExperimentResult>();
		var structuresTimes = new List<ExperimentResult>();
            
		//...

		return new ChartData
		{
			Title = "Call method with argument",
			ClassPoints = classesTimes,
			StructPoints = structuresTimes,
		};
	}
}"В классе ExperimentsTask реализуйте метод BuildChartDataForArrayCreation. Этот метод должен измерять длительность работы метода Run у классов StructArrayCreationTask и ClassArrayCreationTask с помощью Benchmark из прошлого задания.

Нужно измерить время для структур и классов всех размеров, указанных в Constants.FieldCounts. Результаты измерения вернуть в виде объекта ChartData. Дальше в Program.cs эти результаты будут показаны на графиках.

Запустите код на исполнение. Вы должны увидеть первый график скорости работы от количества полей в классе/структуре. На нём должно быть видно, что массивы классов создаются дольше, чем массивы структур.

Эксперимент 2. Передача в метод
Аналогично в файле MethodCallTasks.cs есть ещё пара реализаций ITask. Они вызывают метод, передавая в качестве аргумента класс или структуру с большим количеством полей."using System;
using System.Runtime.CompilerServices;

#pragma warning disable 649

namespace StructBenchmarking;

public class MethodCallWithStructArgumentTask : ITask
{
	private readonly int size;

	private readonly S16 s16;
	private readonly S32 s32;
	private readonly S64 s64;
	private readonly S128 s128;
	private readonly S256 s256;
	private readonly S512 s512;

	public MethodCallWithStructArgumentTask(int size)
	{
		this.size = size;
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	public void Run()
	{
		switch (size)
		{
			case 16:
				PS16(s16);
				break;
			case 32:
				PS32(s32);
				break;
			case 64:
				PS64(s64);
				break;
			case 128:
				PS128(s128);
				break;
			case 256:
				PS256(s256);
				break;
			case 512:
				PS512(s512);
				break;
			default:
				throw new ArgumentException();
		}
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PS16(S16 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PS32(S32 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PS64(S64 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PS128(S128 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PS256(S256 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PS512(S512 o)
	{
	}
}


public class MethodCallWithClassArgumentTask : ITask
{
	private readonly int size;

	private readonly C16 c16;
	private readonly C32 c32;
	private readonly C64 c64;
	private readonly C128 c128;
	private readonly C256 c256;
	private readonly C512 c512;

	public MethodCallWithClassArgumentTask(int size)
	{
		this.size = size;
		c16 = new C16();
		c32 = new C32();
		c64 = new C64();
		c128 = new C128();
		c256 = new C256();
		c512 = new C512();
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	public void Run()
	{
		switch (size)
		{
			case 16:
				PC16(c16);
				break;
			case 32:
				PC32(c32);
				break;
			case 64:
				PC64(c64);
				break;
			case 128:
				PC128(c128);
				break;
			case 256:
				PC256(c256);
				break;
			case 512:
				PC512(c512);
				break;
			default:
				throw new ArgumentException();
		}
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PC16(C16 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PC32(C32 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PC64(C64 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PC128(C128 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PC256(C256 o)
	{
	}

	[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
	void PC512(C512 o)
	{
	}
}"

В том же классе ExperimentsTask реализуйте метод BuildChartDataForMethodCall.

Избавьтесь от дублирования кода в методах BuildChartDataForMethodCall и BuildChartDataForArrayCreation. Возможно, для этого понадобится создать новые классы.

Запустите код на исполнение. Вы должны увидеть второй график, показывающий, что большие классы передаются в метод быстрее, чем большие структуры.

Попробуйте объяснить наблюдаемый результат.

Подсказка
Избавиться от дублирования в коде BuildChartDataForMethodCall и BuildChartDataForArrayCreation поможет паттерн абстрактная фабрика.”