Насколько дорого обходится бокс при явной реализации интерфейса - PullRequest
2 голосов
/ 02 декабря 2008

Текущие руководящие принципы для явной реализации члена рекомендуют:

  • Использование явных членов для аппроксимации частных реализаций интерфейса. Если вам нужно реализовать интерфейс только по инфраструктурным причинам, и вы никогда не ожидаете, что разработчики будут напрямую вызывать методы для этого интерфейса из этого типа, тогда реализуйте члены явно, чтобы "скрыть" их от публичного представления .
  • Предоставьте альтернативный способ доступа к любым явно реализованным элементам, которые подклассам разрешено переопределять.

Хороший пример этого - когда вы хотите реализовать интерфейс IXmlSerializable . Ожидается, что методы ReadXml и WriteXml будут вызываться XmlSerializer и обычно не вызываются напрямую разработчиками.

При предоставлении альтернативного способа явного доступа к элементам, которые вы хотите разрешить переопределять, представляется целесообразным вызывать явно реализованный элемент, чтобы избежать дублирования кода. Учтите следующее:

using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Demo
{
    /// <summary>
    /// Demonstrates explicit implementation of the IXmlSerializable interface.
    /// </summary>
    [Serializable(), XmlRoot(ElementName = "foo")]
    public class Foo : IXmlSerializable
    {
        //============================================================
        //  IXmlSerializable Implementation
        //============================================================
        #region GetSchema()
        /// <summary>
        /// Returns an <see cref="XmlSchema"/> that describes the XML representation of the object.
        /// </summary>
        /// <returns>
        /// An <see cref="XmlSchema"/> that describes the XML representation of the object that is 
        /// produced by the <see cref="IXmlSerializable.WriteXml(XmlWriter)"/> method and consumed by the <see cref="IXmlSerializable.ReadXml(XmlReader)"/> method.
        /// </returns>
        /// <remarks>This method is reserved and should not be used.</remarks>
        XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }
        #endregion

        #region ReadXml(XmlReader reader)
        /// <summary>
        /// Generates an object from its XML representation.
        /// </summary>
        /// <param name="reader">The <see cref="XmlReader"/> stream from which the object is deserialized.</param>
        /// <exception cref="ArgumentNullException">The <paramref name="reader"/> is a <b>null</b> reference (Nothing in Visual Basic).</exception>
        void IXmlSerializable.ReadXml(XmlReader reader)
        {
            // Class state values read from supplied XmlReader
        }
        #endregion

        #region WriteXml(XmlWriter writer)
        /// <summary>
        /// Converts an object into its XML representation.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> stream to which the object is serialized.</param>
        /// <exception cref="ArgumentNullException">The <paramref name="writer"/> is a <b>null</b> reference (Nothing in Visual Basic).</exception>
        void IXmlSerializable.WriteXml(XmlWriter writer)
        {
            // Current class state values written using supplied XmlWriter
        }
        #endregion

        //============================================================
        //  Public Methods
        //============================================================
        #region WriteTo(XmlWriter writer)
        /// <summary>
        /// Saves the current <see cref="Foo"/> to the specified <see cref="XmlWriter"/>.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> stream to which the <see cref="Foo"/> is serialized.</param>
        /// <exception cref="ArgumentNullException">The <paramref name="writer"/> is a <b>null</b> reference (Nothing in Visual Basic).</exception>
        public void WriteTo(XmlWriter writer)
        {
            writer.WriteStartElement("foo");

            ((IXmlSerializable)this).WriteXml(writer);

            writer.WriteEndElement();
        }
        #endregion
    }
}

Мой вопрос касается того, насколько дорогой в этой реализации является бокс метода WriteXml . ((IXmlSerializable) это) .WriteXml (Writer) значительно снизит производительность?

Ответы [ 3 ]

5 голосов
/ 02 декабря 2008

В вашем примере нет бокса ... это просто приведение, и оно разрешимо во время компиляции, поэтому оно не должно влиять на производительность.

Редактировать: Глядя на это с помощью ILDASM, приведение интерфейса даст вам виртуальный вызов метода по сравнению с обычным вызовом метода, но это ничтожно мало (бокс все еще не задействован).

Редактировать 2: Если вы используете структуру вместо класса, ТОГДА вы получите окно, проходящее через интерфейс, с гораздо большими потерями производительности.

3 голосов
/ 02 декабря 2008

Нет, затраты на запись набора данных в XmlWriter значительно превзойдут затраты на бокс.

Бокс состоит из:

  1. Выделение фрагмента памяти из ГХ
  2. Инициализация заголовка с правильной информацией о типе
  3. Копирование данных типа значения в память кучи

По сути, это примерно то же самое, что и конструкция объекта. Если даже один фрагмент данных, который вы пишете в XmlWriter, уже не является строкой, вам все равно придется заплатить эту стоимость, чтобы создать строку для записи.

1 голос
/ 02 декабря 2008

Почему бы просто не вызвать, чтобы они оба вызвали закрытый метод, который выполняет функцию явно реализованного интерфейса?

public void IXmlSerializable.WriteXml( XmlWriter writer )
{
    InternalWriteXml( writer );
}

public void WriteTo(XmlWriter writer)
{
    writer.WriteStartElement("foo");

    InternalWriteXml(writer);

    writer.WriteEndElement();
}

private void InternalWriteXml( XmlWriter writer )
{
    ...
}
...