这听起来像你想做的事,是有一个基类强制子类实现返回子类本身的实例的方法,而不是允许返回从继承的任何其他类型的实例基类。不幸的是,据我所知,这不是你可以做的事情。
但是,您可以强制子类来指定它的类型是基类,从而使基类就可以强制执行的返回值必须是子类中指定的类型。
例如,给定一个名为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();
}
}
如果你真的想确保指定的一般是一样的所属类型,则可能反而让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();
}
}
,如果你创建一个通过不同类型的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();
}
}
不知道这是否得到你想要的东西,但我认为这可能是你可以得到的最接近的东西。
我可以看到这样的例子使用,所以我可以试着去了解你将如何使用这个API。例如,如果允许静态摘要,你将如何使用它?这不过是一个静态工厂方法来创建和配置子实例吗? –