這聽起來像你想做的事,是有一個基類強制子類實現返回子類本身的實例的方法,而不是允許返回從繼承的任何其他類型的實例基類。不幸的是,據我所知,這不是你可以做的事情。
但是,您可以強制子類來指定它的類型是基類,從而使基類就可以強制執行的返回值必須是子類中指定的類型。
例如,給定一個名爲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。例如,如果允許靜態摘要,你將如何使用它?這不過是一個靜態工廠方法來創建和配置子實例嗎? –