簡體   English   中英

如何向下轉換靜態方法生成的實例?

[英]How can I downcast an instance generated by static method?

我有一個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

你不能低估它。 一旦將對象創建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確保TParent的子類型,而new()確保T具有無參數構造函數。

如果您堅持使用靜態方法並且不想使用反射或泛型,那么您還可以考慮使用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);

如果靜態方法不知道要創建的類型,則需要傳遞它。 例如,通過使用泛型:

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

您只能轉換為父類,而不能轉換為子類。 編譯器無法安全地假設對象已正確構造,具有作為子對象安全訪問的所有必需屬性。

要么使用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.
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM