Является ли конструктор класса, который наследуется от другого класса, менее эффективным? - PullRequest
2 голосов
/ 25 апреля 2011

Вопрос

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

Я знаю, что создание класса (то есть вызов конструктора) является дорогостоящим. Мой вопрос: будет ли дороже, если я сделаю так, чтобы этот маленький класс наследовал от другого класса? Некоторые поля просто перейдут в суперкласс, поэтому в основном я могу просто использовать

Примечание. Этот вопрос касается производительности в .NET .

.

Пример ситуации и демонстрация вопроса

Рассмотрим 2 случая:

1. кейс состоит только из одного класса. Это оригинальный класс:

public class ShapeWithOffset{
    public double XOffset { get; private set; }
    public double YOffset { get; private set; }
    public IShape Shape{ get; private set; }

    public ShapeWithOffset(double xOffset, double yOffset, IShape shape){
        //check if arguments are correct/throw ArgumentException if not
        XOffset = xOffset;
        YOffset = yOffset;
        Shape = shape;
    }
    //equality members
}

2. case состоит из 2 классов, где второй наследуется от первого. Второй класс ShapeWithHorizontalAndVerticalOffset обеспечивает ту же функцию, что и ShapeWithOffset в 1. case.

public class ShapeWithHorizontalOffset{
    public double XOffset { get; private set; }
    public IShape Shape { get; private set; }

    public ShapeWithHorizontalOffset(double xOffset, IShape shape){
        //check if arguments are correct/throw ArgumentException if not
        XOffset = xOffset;
        Shape = shape;
    }
    //equality members
}

public class ShapeWithHorizontalAndVerticalOffset : ShapeWithHorizontalOffset{
    public double YOffset { get; private set; }

    public ShapeWithHorizontalAndVerticalOffset(double xOffset, double yOffset, 
                                                IShape shape) : base(xOffset, shape){
        //check if yOffset is correct/throw ArgumentOutOfRangeException if not
        Yffset = yOffset;
    }
    //equality members
}

Мой вопрос: команда var foo = new ShapeWithOffset(20, 10, shape); быстрее, чем
var boo = new ShapeWithHorizontalAndVerticalOffset(20, 10, shape);?

Если бы я использовал композицию вместо наследования, это было бы ... Но как насчет наследования?

Ответы [ 5 ]

8 голосов
/ 25 апреля 2011

Это пахнет преждевременная оптимизация

Ключевыми словами в вашем вопросе являются "... я думаю ...". Если вы знаете, что у вас есть проблемы с производительностью, то найдите узкое место и оптимизируйте его. Если вы ожидаете проблемы с производительностью, не надо! Крайне маловероятно, что любое узкое место в производительности будет вызвано использованием наследования, как вы предлагаете. Но, если вы действительно хотите знать заранее, тестируйте заранее.

5 голосов
/ 25 апреля 2011

Это будет почти то же самое.Вызов базового .ctor будет встроен JITter, и выделение выполняется только один раз.Это будет стоить вам всего несколько байтов в качестве издержек.

Если вы не уверены, попробуйте небольшой тест.

3 голосов
/ 25 апреля 2011

Мой опыт работы с микрооптимизирующим кодом с использованием профилировщика заключается в том, что затраты на вызов метода незначительны.Мои главные достижения в повышении производительности почти всегда заключались в следующем: кэширование часто используемых вычислений, оптимизация глубоких внутренних циклов (обычно с помощью прямой индексации массива, а не перечисления) и избегание ненужных упаковок.Разумеется, все они затмеваются за счет улучшения алгоритма, позволяющего сократить количество итераций (обычно путем введения эвристики, которая может исключить ранние ветви, или путем преобразования задачи в отдельные фазы «агрегирования» и «детализации».)

1 голос
/ 25 апреля 2011

Во-первых, как я уже сказал в своем комментарии, вызов базовых конструкторов (и виртуальных методов) не влияет на производительность в достаточной степени, чтобы оправдать потерю удобства и выразительности, которую он придает вашей программе.Если бы производительность действительно была проблемой в этом случае, структурированные языки не существовали бы.

Теперь, с точки зрения design , вопрос сводится к тому, действительно ли наследование выгодно в действительности.твой случай.Что вызывает вопрос: почему ShapeWithOffset не может быть производным от Shape?Если бы это было возможно, я бы, вероятно, сократил сложность и сделал бы что-то вроде:

public class ShapeWithOffset : Shape
{
    public ShapeWithOffset(double xOffset)
    : this(xOffset, 0.0) {}

    public ShapeWithOffset(double xOffset, double yOffset)
    {
        // TODO - Check if arguments are correct/throw ArgumentException if not.
        XOffset = xOffset;
        YOffset = yOffset;
    }
}

В C # 4 вы даже можете написать:

public ShapeWithOffset(double xOffset, double yOffset = 0.0)
{
    // TODO - Check if arguments are correct/throw ArgumentException if not.
    XOffset = xOffset;
    YOffset = yOffset;
}
0 голосов
/ 25 апреля 2011

обычно говоря о наследовании (не в этом конкретном случае), как сказал Кучана в своей книге (шаблоны проектирования), старайтесь избегать наследования, если в этом нет необходимости, из-за его сложности. и я думаю, что связывание во время выполнения может привести к небольшим проблемам с производительностью, но основная нагрузка на наследование заключается в его сложности при разработке, что гораздо важнее, чем незначительная проблема с производительностью.

EDIT

Теперь я понимаю, что вопрос касается построения: D. Следующий абзац верен для Java, может быть, он верен и для .Net. Я думаю, что если вы явно определите конструктор в своем дочернем классе, это не будет иметь никакого значения, потому что компилятор сначала будет искать конструктор в дочернем классе, если он не найден, он поднимется в иерархии наследования, пока он! найти правильного конструктора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...