Подтвердить что ты не робот

Как я могу скрыть экземпляр, созданный статическим методом?

У меня проблема с программой С#, которая включает в себя следующее:

class Program
{
    static void Main(string[] args)
    {
        Child childInstance = Child.ParseFromA(@"path/to/Afile") as Child;
    }
}

class Parent{
    int property;

    public static Parent ParseFromA(string filename)
    {
        Parent parent = new Parent();
        // parse file and set property here...
        return parent;
    }
}

class Child : Parent
{
    public void SomeAdditionalFunction() { }
}

При запуске этого кода childInstance становится null.

Я попытался выполнить следующее задание с явным приложением, но закончил с исключением:
Child childInstance = (Child)Child.ParseFromA(@"path/to/Afile");

Так как я хочу разбирать некоторые типы файлов в экземплярах Parent и Child, я хочу сохранить конструкцию, которая генерирует экземпляры статическими методами.

Как мне получить правильный childInstance?

4b9b3361

Ответ 1

Вы не можете его понизить. Когда объект был создан как Parent, он всегда будет Parent. Это похоже на попытку спускать a new object() в string: это просто не сработает - какая последовательность символов должна представлять эта строка?

Таким образом, ваше единственное решение - создать правильный объект. Единственный вариант, который я вижу в вашем случае, - сделать ваш статический метод общим:

public static T ParseFromA<T>(string filename) where T : Parent, new()
{
    T t = new T();
    // parse file and set property here...
    return t;
}

Использование:

Child childInstance = Parent.ParseFromA<Child>(@"path/to/Afile");

Общее ограничение T : Parent гарантирует, что T является подтипом Parent, а new() гарантирует, что T имеет конструктор без параметров.

Ответ 2

Если вы настаиваете на использовании статических методов и не хотите использовать отражение или дженерики, то вы также можете использовать ключевое слово new:

class Parent
{
    public static Parent ParseFromA(string filename)
    {
        Parent parent = new Parent();
        parent.Parse(filename);
        return parent;
    }

    protected virtual void Parse(string fileName)
    {
        ...
    }
}

class Child : Parent
{
    public new static Child ParseFromA(string filename)
    {
        Child child = new Child();
        child.Parse(filename);
        return parent;
    }

    protected override void Parse(string fileName)
    {
        base.Parse(fileName);
        SomeAdditionalFunction();
    }
}

Лично я бы просто использовал методы экземпляра.

var child = new Child(...);
child.Parse(...);

Дополнительная строка кода - небольшая цена для оплаты более чистого кода, ИМХО. static ключевое слово не очень хорошо работает с наследованием, как вы можете видеть. Вы также можете всегда обернуть метод экземпляра в метод расширения, если вы хотите, чтобы один-лайнер в конце концов:

public static class ParentEx
{
    public static T ParseFile<T>(this T source, string fileName) : where T : Parent
    {
        source.Parse(fileName);
        return source;
    }
}

а затем

var child = new Child().ParseFile(fileName);

Ответ 3

Если ваш статический метод не знает, какой тип для создания, вам нужно его передать. Например, используя дженерики:

namespace ConsoleApplication18
{
  class Program
  {
    static void Main(string[] args)
    {
      var childInstance = Parent.ParseAs<Child>(@"path/to/Afile");

      childInstance.SomeAdditionalFunction();
    }
  }

  class Parent
  {
    int property;

    public static T ParseAs<T>(string filename) where T : Parent, new()
    {
      var parent = new T();

      // parse file and set property here...
      parent.property = 42;

      return parent;
    }
  }

  class Child : Parent
  {
    public void SomeAdditionalFunction() { }
  }
}

Ответ 4

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

Использовать общий метод, упомянутый выше Heinzi, или использовать параметризованный конструктор и метод instanced parsing в родительском и дочернем классе.

class Parent
{
    public Parent() { }
    public Parent(string fileName) 
    {
         Parse(fileName);
    }

    private void Parse(string fileName)
    {
        // Do your parsing stuff here.
    }
}

class Child : Parent
{
    public Child() { }
    public Child(string fileName) : base(fileName)
    {
         // Parsing is done already done within the constructor of Parent, which is called by base(fileName)
         // All you need to do here is initialize the rest of your child object.
    }
}