如何向下转换由静态方法生成的实例?
我有包含以下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);
或者在基类上使用虚拟,覆盖子类 – Mafii
@Mafii例如方法,是的。尽管如此,你不能覆盖静态方法。 –
如果您的静态方法不知道要创建什么类型的,你需要通过它。例如,使用泛型:
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.
}
}
谢谢!你的解决方案正是我想要做的! 我应用了它,并完美的工作。 – Malboma99
关于你的例子只是一个小问题:将一个'Animal'转换成'Cat'是完全理智的:如果它是一个'Cat',你会收到一个'Cat',如果它不是(null)什么作者)。这里的问题是,如果你创建一个“动物”,你创建一个抽象的动物,不能成为一只猫。这是一个没有一种类型的模型。如果你谈论一个男人,你不是指“约翰”, - 你是指一个抽象的男人。我很确定那是有意的,但我认为从你的例子来看有点不清楚。 – Archeg
@Archeg:你当然是完全正确的。我修改了我的示例,并决定使用一些框架类。 – Heinzi