Опишу, как бы комментировал я
public sealed class DataProvider : IDisposable
{
// nit: Предложил бы названия firstValue, secondValue либо более осмысленные, если возможно
public extern int LongRunningCalculation(int value, int value2);
public extern void Dispose();
}
// nit: сразу бы хотелось видеть уровень доступа и sealed (если класс не планируется наследовать)
// Class2 - дать нормальное имя
// { - перенести на 2ю строку по рекомендациям code style от microsoft (если не принято иных)
class Class2 {
// Синхронизация не нужна, если убрать метод Init, а Create вызвать в статическом конструкторе
private readonly object _sync = new object();
// _ht - дать осмысленное название
// Судя по использованию, value может быть int`ом. Не зачем иметь лишний boxing и проверки на тип
// _ht статический, значит к нему могут быть обращения из разных потоков, лучше сделать его ConcurrentDictionary
// Прям сходу не могу сказать, но, возможно, использовал бы какой то другой тип Dictionary <key, key, val> (самописный или существующий), кажется, так было бы быстрее чем массив в ключе
private static Dictionary<int[], object> _ht;
// nit: хотелось бы имена со смыслом
public int GetValue(int index, int index2)
{
// Лишний метод, удалить. Create вызовем в static конструкторе
Init();
// Если ключ у нас объект, то необходимо реализовать IEqualityComparer для этого Dictionary (иначе не понятно как по нему искать)
var key = new[] {index, index2};
// Проверка на тип не нужна, Dictionary сделаем типа int
if (_ht.ContainsKey(key) & _ht[key].GetType() == typeof(int))
// приведение типов больше не нужно
return ((int)_ht[key]);
// nit: else не обязателен
else
// int не может быть null, будет ошибка, вернуть либо default, либо возвращаемое значение должно быть int?
return null;
}
// Метод удалить, вызовем Create в статическом конструкторе без lock
public void Init()
{
if (_ht == null)
lock (_sync)
Create();
}
// Нет смысла делать метод public, сделать private
public static void Create()
{
// nit: и так видно какой тип создаём, можно использовать var
// Обернуть в using
DataProvider provider = new DataProvider();
// Тут следует инициализировать значение _ht, т.к. ранее оно нигде не создаётся
// Не забыть передать реализацию IEqualityComparer в конструктор
// nit: хотелось бы видеть использование фигурных скобок (если не принят иной code style)
// nit: вместо int можно var
// i и j, похоже, несут какой то смысл, можно попробовать придумать нормальное название (иначе не понятно почему 100 и 12, их можно в константы класса)
// nit: возможно можно использовать Parallel.ForEach
for (int i = 0; i < 100; i++)
for (int j = 1; j <= 12; j++)
_ht[new [] { i, j }] = provider.LongRunningCalculation(i, j);
}
}
А переписал бы так (если не убирать массив в dictionary)
public interface IDataProvider : IDisposable
{
int LongRunningCalculation(int firstValue, int secondValue);
}
public sealed class DataProvider : IDataProvider
{
public extern int LongRunningCalculation(int firstValue, int secondValue);
public extern void Dispose();
}
public sealed class DataProviderService
{
public DataProviderService(IDataProvider dataProvider)
{
_dataProvider = dataProvider;
}
private static readonly ConcurrentDictionary<int[], int?> _calculatedCache = new ConcurrentDictionary<int[], int?>(new CalculatedEqualityComparer());
private readonly IDataProvider _dataProvider;
public int? GetValue(int firstValue, int secondValue)
{
var isNotSupportedValues = firstValue > 100 || firstValue < 0 || secondValue < 1 || secondValue > 12;
if (isNotSupportedValues)
{
return null;
}
var key = new[] { firstValue, secondValue };
if (!_calculatedCache.TryGetValue(key, out var result))
{
result = _dataProvider.LongRunningCalculation(firstValue, secondValue);
_calculatedCache.TryAdd(key, result);
}
return result;
}
}