这听起来像你想要做的,是让一个基类强制一个子类实现一个返回子类本身实例的方法,并且不允许返回从基类继承的任何其他类型的实例班级。不幸的是,据我所知,这不是你能做到的。
但是,您可以强制子类将其类型指定给基类,以便基类可以强制返回值必须是子类指定的类型。
例如,给定一个名为BaseFactory 和BaseFactory<T> 的基类,我们可以创建一个抽象类,要求子类向父类指定创建方法返回的类型。我们包含一个 BaseFactory 类,因此我们可以将 T 限制为仅是 BaseFactory 的子类。
编辑
如果有帮助,我会在下面留下原始答案,但经过一番思考,我想我已经为你找到了更好的解决方案。
您仍然需要基类来获取定义子类型是什么的通用参数。然而现在的区别是基类有一个静态创建方法而不是实例方法。您可以使用此创建方法来创建子类的新实例,并且可以选择在返回之前调用回调以配置新实例上的属性值。
public abstract class BaseFactory { }
public abstract class BaseFactory<TImpl> : BaseFactory where TImpl : BaseFactory, new()
{
public static TImpl Create(Action<TImpl> itemConfiguration = null)
{
var child = new TImpl();
itemConfiguration?.Invoke(child);
return child;
}
}
然后您只需正常创建您的子类,而不必担心覆盖任何方法。
public class Foo : BaseFactory<Foo>
{
public bool IsCompleted { get; set; }
public int Percentage { get; set; }
public string Data { get; set; }
}
public class Bar : BaseFactory<Bar>
{
public string Username { get; set; }
}
那么你就可以直接使用工厂了。
class Program
{
static void Main(string[] args)
{
// Both work
Bar bar1 = Bar.Create();
Foo foo1 = Foo.Create();
// Won't compile because of different Types.
Bar bar2 = Foo.Create();
// Allows for configuring the properties
Bar bar3 = Bar.Create(instanceBar => instanceBar.Username = "Jane Done");
Foo foo2 = Foo.Create(instanceFoo =>
{
instanceFoo.IsCompleted = true;
instanceFoo.Percentage = 100;
instanceFoo.Data = "My work here is done.";
});
}
原答案
BaseFactory<T> 将负责创建 TImpl 的新实例并将其返回。
public abstract class BaseFactory { }
public abstract class BaseFactory<TImpl> : BaseFactory where TImpl : BaseFactory
{
public abstract TImpl WithSomeProp();
}
现在,可以创建您的子类,并从BaseFactory<T> 继承,告诉基类T 代表它自己。这意味着孩子只能返回自己。
public class Foo : BaseFactory<Foo>
{
public override Foo WithSomeProp()
{
return new Foo();
}
}
public class Bar : BaseFactory<Bar>
{
public override Bar WithSomeProp()
{
return new Bar();
}
}
然后你会像这样使用它:
class Program
{
static void Main(string[] args)
{
var obj1 = new Bar();
// Works
Bar obj2 = obj1.WithSomeProp();
// Won't compile because obj1 returns Bar.
Foo obj3 = obj1.WithSomeProp();
}
}
如果您真的想确保指定的泛型与拥有的 Type 相同,则可以改为将 WithSomeProp 设置为受保护方法,以便子类只能看到它。然后,在基类上创建一个可以进行类型检查的公共方法。
public abstract class BaseFactory { }
public abstract class BaseFactory<TImpl> : BaseFactory where TImpl : BaseFactory
{
protected abstract TImpl WithSomeProp();
public TImpl Create()
{
Type myType = this.GetType();
if (typeof(TImpl) != myType)
{
throw new InvalidOperationException($"{myType.Name} can not create instances of itself because the generic argument it provided to the factory is of a different Type.");
}
return this.WithSomeProp();
}
}
public class Foo : BaseFactory<Foo>
{
protected override Foo WithSomeProp()
{
return new Foo();
}
}
public class Bar : BaseFactory<Bar>
{
protected override Bar WithSomeProp()
{
return new Bar();
}
}
class Program
{
static void Main(string[] args)
{
var obj1 = new Bar();
// Works
Bar obj2 = obj1.Create();
// Won't compile because obj1 returns Bar.
Foo obj3 = obj1.Create();
}
}
现在,如果您创建的子类将不同的 Type 传递为 T,则基类将捕获它并抛出异常。
// Throws exception when BaseFactory.Create() is called, even though this compiles fine.
public class Bar : BaseFactory<Foo>
{
protected override Foo WithSomeProp()
{
return new Foo();
}
}
不确定这是否至少能得到你想要的,但我认为这可能是你能得到的最接近的东西。