Как можно создать экземпляр абстрактного класса XmlWriter с помощью XmlWriter.Create(...?

Просто хочу прояснить мое понимание работы XmlWriter и абстрактных классов в целом.

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

Итак, изучая XmlWriter, я обнаружил, что для создания экземпляра XmlWriter вы вызываете XmlWriter.Create(...., который возвращает экземпляр... XmlWriter, который затем можно использовать:

FileStream fs = new FileStream("XML.xml", FileMode.Create);

XmlWriter w = XmlWriter.Create(fs);

XmlSerializer xmlSlr = new XmlSerializer(typeof(TestClass));

xmlSlr.Serialize(fs, tsIn);

Это явно работает, как проверено. Может ли кто-нибудь помочь мне понять, что здесь происходит. Насколько я могу видеть, здесь или не должно быть "экземпляра" для работы здесь?

Ответ 1

Вы не можете создать экземпляр с помощью new, но Create, как он используется здесь, называется так называемым статическим factory; он НЕ является конструктором. Вы обнаружите, что на самом деле объект, возвращаемый Create, не относится к abstract class XmlWriter, а к другому конкретному подклассу.

См. также

Ответ 2

Там нет ничего абстрактного о возвращенном объекте. В среде .NET есть 13 классов, которые реализуют XmlWriter. Они все внутренние, вы можете видеть их имена, только если вы заглянете в исходный код с помощью Reflector.

Не знать имена этих 13 классов сами по себе очень ценны как для вас, так и для Microsoft. Для вас, потому что вам не нужно изучать детали выбора правильного. Для Microsoft, поскольку они могут полностью изменить реализацию, даже имя, этих классов и кода никогда не заметят.

Это называется Factory Pattern.

Ответ 3

Это то, что называется factory pattern.

В этом случае абстрактный класс также действует как factory, ответственный за создание конкретных экземпляров классов, которые расширяются.

Таким образом, ответственность за создание правильного класса передается factory, нередко factory будет принимать решения о том, какой класс создавать в зависимости от некоторых параметров, которые вы передаете, или других вещей, таких как config/environment и т.д..

Ответ 4

Спасибо. Как только я проверил тип возвращаемого объекта, я получил тип, полученный из XmlWriter. Что меня сбивало с толку, было то, что я не ожидал, что абстрактный базовый класс сможет ссылаться на подклассы его самого.

.NET должен определить тип конкретного XmlWriter для возврата на основе входных аргументов.

Мне кажется, что XmlWriter работает немного менее интуитивно, чем другие реализации, которые я видел со времени чтения всех комментариев здесь. Примеры, например, в приведенной ниже ссылке, используют метод Create из конкретных классов.

http://www.codeproject.com/KB/architecture/CSharpClassFactory.aspx

Я выбил код здесь, чтобы доказать, что реализация функциональности с помощью метода Create в абстрактном классе возможна. Метод create абстрактного класса действительно может ссылаться на производные типы, как показано здесь:

  using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace TestFactoryPattern
    {
        public abstract class Input
        {
            public int Val;
        }

        public class InputObjA : Input
        {
            public InputObjA()
            {
                Val = 1;
            }
        }

        public class InputObjB : Input
        {
            public InputObjB()
            {
                Val = 2;
            }
        }

        public abstract class MyXmlWriter
        {
            public static int InputVal;

            public static MyXmlWriter Create(Input input)
            {
                InputVal = input.Val;

                if (input is InputObjA)
                {
                    return new MyObjAXmlWriter();
                }
                else if (input is InputObjB)
                {
                    return new MyObjBXmlWriter();
                }
                else
                {
                    return new MyObjAXmlWriter();
                }
            }

            public abstract void WriteMyXml();
        }

        public class MyObjAXmlWriter : MyXmlWriter
        {
            public override void WriteMyXml()
            {
                Console.WriteLine("Input A Written: " + InputVal);
            }
        }

        public class MyObjBXmlWriter : MyXmlWriter
        {
            public override void WriteMyXml()
            {
                Console.WriteLine("Input B Written: " + InputVal);
            }
        }

        public class Program
        {
            public static void Main()
            {
                InputObjA a = new InputObjA();

                MyXmlWriter myXml1 = MyXmlWriter.Create(a);

                myXml1.WriteMyXml();

                InputObjB b = new InputObjB();

                MyXmlWriter myXml2 = MyXmlWriter.Create(b);

                myXml2.WriteMyXml();

            }


  }
}

Спасибо всем за ответы и ввод.