#c# #optimization #casting #type-conversion
#c# #оптимизация #Кастинг #преобразование типов
Вопрос:
Я хотел бы оптимизировать следующую последовательность, потому что время выполнения имеет линейный рост, чем больше операций as я добавляю. Есть ли более разумный способ реализовать это в том же классе без использования дополнительных вспомогательных классов / шаблонов? Заранее спасибо (и извините за правки ..)!
public void SomeMethod(ClassZero foo)
{
var targetName = "";
var a = foo as ClassA;
if (a != null) targetName = a.DoSomething();
var b = foo as ClassB;
if (b != null) targetName = b.DoSomethingElse();
var c = foo as ClassC;
if (c != null) targetName = c.DoSomethingEntirelyElse();
var d = foo as ClassD;
if (c != null) targetName = d.DoSomethingInAnotherParallelWorld();
var furtherUse = localVariable.Process(targetName);
}
Комментарии:
1. Настоятельно рекомендую вам изучить, можете ли вы использовать абстрактный базовый класс или интерфейс вместо этого. Кроме того, я бы предположил, что вы, вероятно, могли
return
бы, если бы нашли совпадение, чего не делает ваш код. Это предотвратило бы любые посторонние проверки типов. Кроме того, если вам нужно проверить тип, вам придется потратить на это время. Я бы сомневался, что вы обнаружите узкое место в производительности при проверке типов здесь.2. Я бы пересмотрел свой дизайн, вы могли бы просто поработать над интерфейсом в этом месте и внедрить конкретную реализацию метода, который вы вызываете прямо здесь. В основном ClassA и ClassB реализуют IDoWork, который содержит метод void DoWork() . И вы просто вызываете его непосредственно в приведенном выше коде
3.
without using further helper classes / patterns?
Когда ваш код нуждается в улучшении, вы, скорее всего, захотите использовать какой-либо вспомогательный класс / шаблон для достижения этой цели. Вы, по сути, запрещаете лучшие решения своей проблемы каждый раз, когда предоставляете себе такое ограничение. Когда вы сталкиваетесь с подобными проблемами, вы должны спросить, как я могу использовать вспомогательный класс или скороговорку для инкапсуляции механики / поведения моей программы.4. Вы действительно ожидаете, что здесь будет так много классов, что их линейная проверка на самом деле будет проблемой производительности? Вероятно, для этого вам понадобятся десятки, если не сотни тысяч различных классов, и если у вас здесь так много классов, у вас будет гораздо больше, чем просто проблемы с производительностью. Этот код станет недоступным для поддержки задолго до того, как это станет проблемой производительности.
5. @Dominik yeach, не совсем ясно прочитал вопрос, спасибо.
Ответ №1:
В идеале, вместо того, чтобы запрашивать тип у базового класса и выбирать другой открытый метод, у вас должен быть один вызов метода в базовом классе (или, что еще лучше, интерфейс), который может вызываться независимо от базовой реализации.
В общем, это называется полиморфизмом, при котором вы можете одинаково обрабатывать несколько производных классов при взаимодействии с ними как с их базовым классом.
public void SomeMethod(ClassZero foo)
{
var targetName = "";
targetName = foo.GetTargetName();
var furtherUse = localVariable.Process(targetName);
}
И в других местах:
public abstract class ClassZero
{
public abstract string GetTargetName();
}
public class ClassA : ClassZero
{
public override string GetTargetName()
{
return DoSomething();
}
}
public class ClassB : ClassZero
{
public override string GetTargetName()
{
return DoSomethingElse();
}
}
В качестве альтернативы вы могли бы использовать интерфейс. Это часто было бы предпочтительнее, поскольку это явный контракт с классом, для которого он предоставляет функцию, в данном случае, для получения TargetName . Это немного менее запутанно по сравнению с абстрактным методом в абстрактном базовом классе. Также хорошо, если у вас нет базового класса ClassZero .
public interface ITargetNameGenerator
{
string GetTargetName();
}
public void SomeMethod(ITargetNameGenerator foo)
{
var targetName = "";
targetName = foo.GetTargetName();
var furtherUse = localVariable.Process(targetName);
}
public class ClassA : ClassZero, ITargetNameGenerator
{
public string GetTargetName()
{
return DoSomething();
}
}
//etc...
Комментарии:
1. Я определенно согласен с тем, что это правильное решение, но может быть полезно показать, как реализовать это с помощью интерфейсов, если у них нет права собственности на ClassZero. Что-то вроде public ClassA : ClassZero, igettargetname и т.д.