Хочу упростить код, но для этого нужно использовать reflections. Можно по другому?
Делаю автоматическое создание ставок на исход игры. после игры получаю объект матча, в котором содержится статистика по убийствам, заработанному золоту и т.д. Во время начала матча ставка выбирается рандомно, в зависимости от того какая ставка выбирается, вызывается соответствующий асинхронный метод, который запускает саму ставку, ждет конца матча и подсчитывает результаты. Проблема в том что у меня с дюжину такие методов с идентичным кодом, разница лишь в том какая переменная объекта используется для подсчета результата. Я могу использовать reflection и передавать в метод string с названием переменной, но говорят что reflection это турбо плохо. можно это реализовать как-то по другому?
Thread riotMatchesTask = new Thread(() => GetCurrentMatchTask().Wait());
async Task GetCurrentMatchTask()
{
while (true)
{
try
{
//Пока не в игре, проверяем стартанула ли игра. Когда стартанула рандомно
//выбираем ставку и запускаем ее
var CurrentGame = await api.Spectator.GetCurrentGameAsync();
bool procked = false;
if (procked == false && getchance(20))
{
await Prediction_MAX_Kills(CurrentGame).ConfigureAwait(false);
procked = true;
}
if (procked == false && getchance(20))
{
await Prediction_MAX_gold(CurrentGame).ConfigureAwait(false);
procked = true;
}
//и т.д. на каждую ставку свой метод
await Task.Delay(2000).ConfigureAwait(false);
}
catch (Exception ex)
{
if (!ex.InnerException.Message.Contains("Data not found")) //Ожидаемо
_logWriter.LogWriterTask(ex, "GetCurrentMatchTask_1");
}
}
}
async Task Prediction_MAX_gold(SpectatorEndpoint.CurrentGame CurrentGame)
{
//запуск ставки
...
//ожидание конца игры
...
//получаю данные об исходе игры
var onMatch = await api.Match.GetMatchAsync(CurrentGame.currentGameID);
var FinParticipants = onMatch.Info.Participants.ToArray(); //получаю игроков
foreach (var Participant in FinParticipants) //для каждого игрока формирую статистику по параметру
{
var vFlag = Participant.GoldEarned; //!!!параметр
Players.Add(new cPlayersObject.PlayersObject()
{
name = Participant.SummonerName,
champ = Participant.ChampionName,
Flag = vFlag
});
}
}
Каждый метод Prediction_MAX_"что-то" это идентичный код, за исключение строчки с параметром. если я сделаю метод с reflection
foreach (var Participant in FinParticipants)
{
var val = Participant.GetType().GetProperty(_Flag).GetValue(Participant, null);
var vFlag = (long)Convert.ChangeType(val, typeof(long));
Players.Add(new cPlayersObject.PlayersObject()
{
name = Participant.SummonerName,
champ = Participant.ChampionName,
Flag = vFlag
});
}
и буду в него передавать string _Flag с названием параметра, это удалит лишние 3000 строк кода. Как можно сделать тоже самое, но без reflection?
Ответы (1 шт):
Добавляем в метод Prediction_MAX параметр-делегат, который принимает тип Participant и возвращает значение того же типа, что и Flag.
Внутри метода этот делегат вызывается.
async Task Prediction_MAX(... CurrentGame, Func<Participant, long> func)
{
...
foreach (var Participant in FinParticipants)
{
Players.Add(new cPlayersObject.PlayersObject()
{
...
Flag = func(Participant)
});
}
}
Вызываем этот метод следующим образом:
await Prediction_MAX(CurrentGame, participant => participant.Kills)
Можно параметр именовать покороче:
await Prediction_MAX(CurrentGame, p => p.GoldEarned)
Я бы порекомендовал исправить нейминг на общепринятый.
PascalCase для имён свойств и методов, camelCase для локальных переменных и параметров.
Очень уж глаз цепляется.