C# 重构:扩展抽象类但返回实现类

C# 重构:扩展抽象类但返回实现类,c#,generics,interface,refactoring,C#,Generics,Interface,Refactoring,目前我有: class EntityFOO { EntityFOO LoadFromXml(XDocument) {...} EntityFOO LoadFromDB(string) {...} } class EntityBAR { EntityBAR LoadFromXml(XDocument) {...} EntityBAR LoadFromDB(string) {...} } 我想重构并提取一个接口。我想要这样的东西: abstract class E

目前我有:

class EntityFOO
{
    EntityFOO LoadFromXml(XDocument) {...}
    EntityFOO LoadFromDB(string) {...}
}

class EntityBAR
{
    EntityBAR LoadFromXml(XDocument) {...}
    EntityBAR LoadFromDB(string) {...}
}
我想重构并提取一个接口。我想要这样的东西:

abstract class Entity
{
    static string DatabaseConnectionString = "shared_across_implementations";

    abstract Entity LoadFromXml(XDocument);
    abstract Entity LoadFromDB(string);
}

class EntityBAR : Entity
{
    EntityBAR LoadFromXml(XDocument) {...}
    EntityBAR LoadFromDB(string) {...}
}
请注意,
实体
的实现返回它们自己的类型
EntityBAR
,而不是父
实体
。假设我必须以某种方式使用

类似的东西

abstract class Entity<T> where T : Entity<T>
{
    static string DatabaseConnectionString = "shared_across_implementations";

    abstract T LoadFromXml(XDocument);
    abstract T LoadFromDB(string);
}

class EntityBAR : Entity<EntityBAR>
{
    EntityBAR LoadFromXml(XDocument) {...}
    EntityBAR LoadFromDB(string) {...}
}
当然,除非构建/初始化对象的操作非常繁重,并且本身涉及其他依赖项。在这种情况下,构造函数并不总是这样做的安全场所,设计将调用单独的工厂对象。这些可以是基于实例的,并返回这些实例

但是在对象本身上有一个基于实例的初始化步骤本质上意味着使用代码需要手动记住构建任何给定对象是一个两步过程。这会带来潜在的bug和其他逻辑问题。

类似的问题?:

abstract class Entity<T> where T : Entity<T>
{
    static string DatabaseConnectionString = "shared_across_implementations";

    abstract T LoadFromXml(XDocument);
    abstract T LoadFromDB(string);
}

class EntityBAR : Entity<EntityBAR>
{
    EntityBAR LoadFromXml(XDocument) {...}
    EntityBAR LoadFromDB(string) {...}
}
当然,除非构建/初始化对象的操作非常繁重,并且本身涉及其他依赖项。在这种情况下,构造函数并不总是这样做的安全场所,设计将调用单独的工厂对象。这些可以是基于实例的,并返回这些实例


但是在对象本身上有一个基于实例的初始化步骤本质上意味着使用代码需要手动记住构建任何给定对象是一个两步过程。这会带来潜在的bug和其他逻辑问题。

如果我在方法上放置
public
s,在类方法上放置
override
s,并在签名中放置变量,那么构建似乎是正常的。真的没想到会这样:o)@NikolaiDante:我认为设计本身可以进行一些改进,使问题本身变得毫无意义。这些
Load*
,不是工厂,它们实际上不实例化对象(创建),它们只是设置给定对象的字段(加载)。即使没有
where T
@dialex,
where T
约束,您的解决方案也可以工作:嗯,
where T
约束主要是一种健全性检查,以确保继承树不会获得超出预期范围的随机类型。它会“起作用”,但可能会与其他你无法控制的类型发生冲突。如果这些方法不是工厂,那么它们可能不应该返回类型?如果它们只是用来初始化对象,那么我仍然倾向于使用构造函数。除非有令人信服的理由不这样做。(例如使用重操作初始化,在这种情况下将调用工厂对象。)@David,您在
class EntityBAR
处有一个小错误,构造函数与基类同名。如果我在方法上放置
public
s,在类方法上放置
override
s,则似乎构建正常,和签名中的变量。真的没想到会这样:o)@NikolaiDante:我认为设计本身可以进行一些改进,使问题本身变得毫无意义。这些
Load*
,不是工厂,它们实际上不实例化对象(创建),它们只是设置给定对象的字段(加载)。即使没有
where T
@dialex,
where T
约束,您的解决方案也可以工作:嗯,
where T
约束主要是一种健全性检查,以确保继承树不会获得超出预期范围的随机类型。它会“起作用”,但可能会与其他你无法控制的类型发生冲突。如果这些方法不是工厂,那么它们可能不应该返回类型?如果它们只是用来初始化对象,那么我仍然倾向于使用构造函数。除非有令人信服的理由不这样做。(例如使用繁重的操作初始化,在这种情况下将调用工厂对象。)@David,您在
class EntityBAR
处有一个小错误,构造函数的名称与基类相同。