Множество объектов со схожей логикой. Структура или класс?
Вопрос на стыке оптимизации и ООП. У меня есть множество классов или структур(пока что структуры) которые представляют контейнеры для различных команд для IoT устройств. Буду передавать их по сети между сервисами, упаковывать в программируемые UI-пользователем скрипты, ставить в очереди, кто знает что еще придет в голову. Поэтому так заморочился. У команд практически одинаковая логика за исключением количества параметров. Вот пример одной из них:
public struct Set_ct_abx : IDeviceCommand
{
public int CommandId { get; }
int? DeviceId;
private string JsonPreString;
private string JsonPostString;
public Set_ct_abx(int colorTemperature, BulbStateChangingEffect effect, int duration)
{
CommandId = CommandIdCounter++;
DeviceId = null;
JsonPreString = "{\"id\":";
JsonPostString = $",\"method\":\"set_ct_abx\",\"params\":[{colorTemperature}, \"{effect}\", {duration}]}}";
}
public void SetTargetId(int deviceId)
{
DeviceId = deviceId;
}
public string GetJson()
{
if (DeviceId != null)
return JsonPreString + DeviceId + JsonPostString;
else
throw new Exception("Device ID is not set to the command " + CommandId);
}
}
Все кроме вот этих строчек повторяется из раза в раз
public struct Set_ct_abx : IDeviceCommand
{
public Set_ct_abx(int colorTemperature, BulbStateChangingEffect effect, int duration)
{
JsonPreString = "{\"id\":";
JsonPostString = $",\"method\":\"set_ct_abx\",\"params\":[{colorTemperature}, \"{effect}\", {duration}]}}";
}
}
Все бы ничего, но таких видов команд более 20-ти для каждого устройства. А если я захочу изменить что-то в общей логике? Это же ад будет. Лучше вынести в общий класс, но структуры не наследуются, C# 7.3 ругается на реализацию в интерфесах. Но в тоже время эти команды будут генерироваться десятками в секунду. Выделение места на куче, сборка мусора.. Реализация классами это удар по производительности, не знаю насколько большой. Но что-то как-то стремно. Что думаете?
Ответы (1 шт):
- Вы решаете задачу "в лоб". Это дешево и эффективно, но только в краткосрочной перспективе. Я бы использовал более подходящие для этого технологии.
- С вашими объемами данных совершенно всё равно, что использовать, классы или структуры.
Вот простой пример с классом, как можно использовать JSON сериализацию.
Класс с данными у меня получился такой
public class DeviceData
{
[JsonPropertyName(name: "id")]
public int? Id { get; set; }
[JsonPropertyName(name: "method")]
public string Method { get; set; }
[JsonPropertyName(name: "params")]
public List<int> Params { get; set; }
}
А вот так я проверил, что всё работает
DeviceData deviceData = new DeviceData
{
Id = 232,
Method = "set_ct_abx",
Params = new List<int>
{
1000,
1234,
-53456
}
};
JsonSerializerOptions options = new JsonSerializerOptions
{
WriteIndented = true, // форматирует Json в человекочитаемый вид
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping // человекочитаемый юникод
};
string result = JsonSerializer.Serialize(deviceData, typeof(DeviceData), options);
MessageBox.Show(result);
Вывод получился такой
{
"id": 232,
"method": "set_ct_abx",
"params": [
1000,
1234,
-53456
]
}
Для работы вышеуказанного кода вам потребуeтся .NET Core 3.1 (там кстати C# 8.0) и следующие неймспейсы:
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Text.Encodings.Web;
А если переписать ваш код, то получится следующее:
public struct Set_ct_abx : IDeviceCommand
{
public int CommandId { get; }
public DeviceData DeviceData { get; private set; }
public Set_ct_abx(int colorTemperature, BulbStateChangingEffect effect, int duration)
{
CommandId = CommandIdCounter++;
DeviceData = new DeviceData
{
Id = null,
Method = "set_ct_abx",
Params = new List<int>
{
colorTemperature,
effect,
duration
}
};
}
public void SetTargetId(int deviceId)
{
if (DeviceData != null)
DeviceData.Id = deviceId;
else
throw new Exception("Device Data is not set to the command " + CommandId);
}
public string GetJson()
{
if (DeviceData?.Id != null)
return JsonSerializer.Serialize(DeviceData, typeof(DeviceData));
else
throw new Exception("Device ID is not set to the command " + CommandId);
}
}