如何向下转换静态方法生成的实例?

时间:2016-10-28 08:38:46

标签: c#

我的C#程序存在问题,其中包括以下内容:

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");

由于我想将某些类型的文件解析为ParentChild实例,我想保留通过静态方法生成实例的设计。

我应该如何获得合适的childInstance

4 个答案:

答案 0 :(得分:23)

你无法贬低它。将对象创建为r.dbDrop('test').run(conn, function(result) { console.log(result) // Will result in error }); 后,始终ReqlOpFailedError: Database 'test' is ambiguous; there are multiple databases with that name in r.dbDrop("test")。这就像试图将Parent向下转换为Parent:这是行不通的 - 这个字符串应该代表哪个字符序列?

因此,您唯一的解决方案是创建正确的对象。我在你的案例中看到的唯一选择是使你的静态方法通用:

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具有无参数构造函数。

答案 1 :(得分:3)

如果您坚持使用静态方法并且不想使用反射或泛型,那么您还可以考虑使用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);

答案 2 :(得分:2)

如果您的静态方法不知道要创建的类型,则需要传递它。例如,使用泛型:

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() { }
  }
}

答案 3 :(得分:1)

您只能转换为父类,而不能转换为子类。编译器无法安全地假设对象已正确构造,具有作为子对象安全访问的所有必要属性。

使用Heinzi上面提到的泛型方法,或者在父类和子类中使用参数化构造函数和实例解析方法。

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.
    }
}