如何向下转换由静态方法生成的实例?
本文关键字:实例 静态方法 转换 | 更新日期: 2023-09-27 18:15:25
我有一个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");
由于我想将某些类型的文件解析为Parent
和Child
实例,因此我想保留通过静态方法生成实例的设计。
我应该如何得到一个适当的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
确保T
是Parent
的子类型,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.
}
}