我原本认为我理解了泛型约束,直到我遇到这个问题。
public class DBase<T> : DbContext, IDisposable where T : DBase<T>
如何把T作为DBase<T>
?
如果可以的话,这意味着什么?
这段代码能够通过编译并正常运行。我不是在修复问题。我只是不明白它。
它被用在这里:
public class ChildDb : DBase<ChildDb>
对我来说,这仍然不可理解。它将自身作为类型参数传递?
我原本认为我理解了泛型约束,直到我遇到这个问题。
public class DBase<T> : DbContext, IDisposable where T : DBase<T>
如何把T作为DBase<T>
?
如果可以的话,这意味着什么?
这段代码能够通过编译并正常运行。我不是在修复问题。我只是不明白它。
它被用在这里:
public class ChildDb : DBase<ChildDb>
对我来说,这仍然不可理解。它将自身作为类型参数传递?
如何将
T
设为DBase<T>
?
没有限制阻止泛型参数从自身派生。虽然你所给出的示例不太容易理解,但是对于一个 顶点 / 点,这种情况就很常见了。
摘自维基百科:
在几何学中,顶点(复数:vertices或vertexes)是两条或多条曲线、直线或边相交的点。根据这个定义,两条线相交成角的点以及多边形和多面体的角落都是顶点。如何描述顶点(一个点)?// very simplified example
public class Vertex
{
public int X { get; set; }
public int Y { get; set; }
}
public class Vertex<TVertex> : Vertex
where TVertex : Vertex<TVertex>
{
public IEnumerable<TVertex> Vertices { get; set; }
}
这是一个通用版本的说法:
public Vertex2
{
public IENumerable<Vertex2> Vertices { get; set; }
}
Vertices
将始终是IEnumerable<Vertex2>
,并且允许Vertices成为派生类的正确方法是使用这种类型的自引用泛型。
对不起Erik,我在细节中失去了重点。递归给我带来了什么好处?
使用Vertex2
,我们派生类型失去了对其他派生属性的访问:
public class MyVertex2: Vertex2
{
public int Id { get; set; }
}
所以
var a = new MyVertex2 {Id = 1 };
var b = new MyVertex2 { Id = 2 };
a.Vertices = new List<Vertex2> { b };
b.Vertices = new List<Vertex2> { a };
// can't access Id because it's a Vertex2 not a MyVertex2
var bId = a.Vertices.First().Id;
当然你可以强制转换,但这样会在所有地方都进行转换(这不符合DRY原则)...而且如果它不是MyVertex类型的话(可能会出现MullReferencesException或InvalidCastException异常)。
public class MyVertex: Vertex<MyVertex>
{
public int Id { get; set; }
}
var a = new MyVertex {Id = 1 };
var b = new MyVertex { Id = 2 };
a.Vertices = new List<MyVertex > { b };
b.Vertices = new List<MyVertex > { a };
var bId = a.Vertices.First().Id;
// or even
var aId = a.Vertices.First().Vertices.First();
Vertices
类。 - Erik Philipspublic abstract class Control
{
public string Id { get; set; }
}
public abstract class ControlBuilder<TBuilder, TControl>
where TBuilder : ControlBuilder<TBuilder, TControl>, new()
where TControl : Control, new()
{
protected TControl control;
protected ControlBuilder()
{
control = new TControl();
}
public static TBuilder With()
{
return new TBuilder();
}
public TControl Build()
{
control;
}
public TBuilder Id(string id)
{
control.Id = id;
return (TBuilder)this;
}
}
ControlBuilder<TBuilder, TControl>
作为TBuilder
的约束条件,你如何从Id
方法中返回一个TBuilder
?如果您返回它,那么在调用方法链中的.Id("something")之后,它将不显示派生类方法,只会显示ControlBuilder<TBuilder,TControl>
的方法。如果您问为什么不返回ControlBuilder<TBuilder,TControl>
,因为如果您返回它,在调用方法链中的.Id("something")之后,它将不显示派生类方法,只会显示ControlBuilder<TBuilder,TControl>
的方法。假设我们创建了一个用于构建TextBox
的TextBoxBuilder
:public class TextBox : Control
{
public string Text { get; set; }
}
public class TextBoxBuilder : ControlBuilder<TextBoxBuilder, TextBox>
{
public TextBoxBuilder Text(string text)
{
control.Text = text;
return this;
}
}
var txt = TextBoxBuilder.With().Id("textBox1").Text("Hello!").Build();
TextBoxBuilder.With().Id("textBox1")
方法后,TextBoxBuilder
的方法将不会出现,你只能看到基本的ControlBuilder
的方法。我建议你试着去操作一下,以便更好地理解。希望能帮到你 :) - Reza Aghaei