.NET Self Reference
Clash Royale CLAN TAG#URR8PPP
up vote
8
down vote
favorite
I am evaluating an open source CMS called Piranha (http://piranhacms.org/) for use in one of my projects. I found the following code interesting and a bit confusing, at least to me. Can some help me understand why the class is inheriting from a base of same type?
public abstract class BasePage<T> : Page<T> where T : BasePage<T>
/// <summary>
/// Gets/sets the page heading.
/// </summary>
[Region(SortOrder = 0)]
public Regions.PageHeading Heading get; set;
If a class of BasePage<T>
is being defined, why inherit from Page<T> where T: BasePage<T>
? What specific purpose does it serve?
c# architecture .net cms
add a comment |Â
up vote
8
down vote
favorite
I am evaluating an open source CMS called Piranha (http://piranhacms.org/) for use in one of my projects. I found the following code interesting and a bit confusing, at least to me. Can some help me understand why the class is inheriting from a base of same type?
public abstract class BasePage<T> : Page<T> where T : BasePage<T>
/// <summary>
/// Gets/sets the page heading.
/// </summary>
[Region(SortOrder = 0)]
public Regions.PageHeading Heading get; set;
If a class of BasePage<T>
is being defined, why inherit from Page<T> where T: BasePage<T>
? What specific purpose does it serve?
c# architecture .net cms
5
blogs.msdn.microsoft.com/ericlippert/2011/02/03/â¦
â David Arno
4 hours ago
4
Despite the downvotes and close votes, I think the community got it wrong on this one. This is a clearly-stated question having to do with a specific and non-trivial design decision, the very essence of what this site is about.
â Robert Harvey
4 hours ago
1
@RobertHarvey: could not agree more, but I guess we will not be able to educate persons like gnat on this ;-) And he is obviously not the only one who mistakenly believes any question with some code in it need to be closed.
â Doc Brown
3 hours ago
Just hang around and reopen it when it gets closed.
â David Arno
3 hours ago
add a comment |Â
up vote
8
down vote
favorite
up vote
8
down vote
favorite
I am evaluating an open source CMS called Piranha (http://piranhacms.org/) for use in one of my projects. I found the following code interesting and a bit confusing, at least to me. Can some help me understand why the class is inheriting from a base of same type?
public abstract class BasePage<T> : Page<T> where T : BasePage<T>
/// <summary>
/// Gets/sets the page heading.
/// </summary>
[Region(SortOrder = 0)]
public Regions.PageHeading Heading get; set;
If a class of BasePage<T>
is being defined, why inherit from Page<T> where T: BasePage<T>
? What specific purpose does it serve?
c# architecture .net cms
I am evaluating an open source CMS called Piranha (http://piranhacms.org/) for use in one of my projects. I found the following code interesting and a bit confusing, at least to me. Can some help me understand why the class is inheriting from a base of same type?
public abstract class BasePage<T> : Page<T> where T : BasePage<T>
/// <summary>
/// Gets/sets the page heading.
/// </summary>
[Region(SortOrder = 0)]
public Regions.PageHeading Heading get; set;
If a class of BasePage<T>
is being defined, why inherit from Page<T> where T: BasePage<T>
? What specific purpose does it serve?
c# architecture .net cms
c# architecture .net cms
asked 5 hours ago
Xami Yen
573
573
5
blogs.msdn.microsoft.com/ericlippert/2011/02/03/â¦
â David Arno
4 hours ago
4
Despite the downvotes and close votes, I think the community got it wrong on this one. This is a clearly-stated question having to do with a specific and non-trivial design decision, the very essence of what this site is about.
â Robert Harvey
4 hours ago
1
@RobertHarvey: could not agree more, but I guess we will not be able to educate persons like gnat on this ;-) And he is obviously not the only one who mistakenly believes any question with some code in it need to be closed.
â Doc Brown
3 hours ago
Just hang around and reopen it when it gets closed.
â David Arno
3 hours ago
add a comment |Â
5
blogs.msdn.microsoft.com/ericlippert/2011/02/03/â¦
â David Arno
4 hours ago
4
Despite the downvotes and close votes, I think the community got it wrong on this one. This is a clearly-stated question having to do with a specific and non-trivial design decision, the very essence of what this site is about.
â Robert Harvey
4 hours ago
1
@RobertHarvey: could not agree more, but I guess we will not be able to educate persons like gnat on this ;-) And he is obviously not the only one who mistakenly believes any question with some code in it need to be closed.
â Doc Brown
3 hours ago
Just hang around and reopen it when it gets closed.
â David Arno
3 hours ago
5
5
blogs.msdn.microsoft.com/ericlippert/2011/02/03/â¦
â David Arno
4 hours ago
blogs.msdn.microsoft.com/ericlippert/2011/02/03/â¦
â David Arno
4 hours ago
4
4
Despite the downvotes and close votes, I think the community got it wrong on this one. This is a clearly-stated question having to do with a specific and non-trivial design decision, the very essence of what this site is about.
â Robert Harvey
4 hours ago
Despite the downvotes and close votes, I think the community got it wrong on this one. This is a clearly-stated question having to do with a specific and non-trivial design decision, the very essence of what this site is about.
â Robert Harvey
4 hours ago
1
1
@RobertHarvey: could not agree more, but I guess we will not be able to educate persons like gnat on this ;-) And he is obviously not the only one who mistakenly believes any question with some code in it need to be closed.
â Doc Brown
3 hours ago
@RobertHarvey: could not agree more, but I guess we will not be able to educate persons like gnat on this ;-) And he is obviously not the only one who mistakenly believes any question with some code in it need to be closed.
â Doc Brown
3 hours ago
Just hang around and reopen it when it gets closed.
â David Arno
3 hours ago
Just hang around and reopen it when it gets closed.
â David Arno
3 hours ago
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
5
down vote
accepted
Can some help me understand why the class is inheriting from a base of same type?
It's not, it's inheriting from Page<T>
, but T
itself is constrained to be parameterized by a type that is derived from BasePage<T>
.
To infer why, you have to look at how the type parameter T
is actually used.
After some digging, as you move up the inheritance chain, you'll come up upon this class:
(github)
public class GenericPage<T> : PageBase where T : GenericPage<T>
public bool IsStartPage
get return !ParentId.HasValue && SortOrder == 0;
public GenericPage() : base()
public static T Create(IApi api, string typeId = null)
return api.Pages.Create<T>(typeId);
As far as I can see, the only purpose for the generic constraint is to make sure that the Create
method returns the least abstract type possible.
Not sure if it's worth it, though, but perhaps there's some good reason behind it, or it could be only for convenience, or maybe there's no too much substance behind it and it's just an overly elaborate way to avoid a cast (BTW, I'm not implying that is the case here, I'm just saying that people do that sometimes).
Note that this doesn't allow them to avoid reflection - the api.Pages
is a repository of pages that obtains typeof(T).Name
, and passes it as the typeId
to the contentService.Create
method (see here).
add a comment |Â
up vote
0
down vote
One common use of this is related to the concept of self-types: a type parameter that resolves to the current type. Let's say you want to define an interface with a clone()
method. The clone()
method must always return an instance of the class on which it was called. How do you declare that method? In a generics system that has self-types, it's easy. You just say it returns self
. So if I have a class Foo
, the clone method must be declared to return Foo
. In Java and (from a cursory search) C#, this isn't an option. You instead see declarations like what you see in this class. It's important to understand that this is not the same thing as a self-type and the restrictions it provides are weaker. If you have a Foo
and a Bar
class that both derive from BasePage
, you can (if I am not mistaken) define Foo to be parameterized by Bar
. That might be useful but I think typically, most of the time, this will be used like a self-type and it's just understood that even though you can goof around and substitute with other types, it's not something you should do. I played around with this idea long ago but came to the conclusion that it wasn't worth the effort because the limitations of Java generics. C# generics are of course more fully featured but it seems to have this same limitation.
The other time this approach get's used it when you are building graph-like types such as trees or other recursive structures. The declaration allows types to meet the requirements of Page but further refine the type. You might see this in a tree structure. For example a Node
might be parameterized by Node
to allow for implementations to define that they aren't just Trees containing any type of Node but a specific sub-type of Node (usually their own type.) I think that's more of what's going on here.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
accepted
Can some help me understand why the class is inheriting from a base of same type?
It's not, it's inheriting from Page<T>
, but T
itself is constrained to be parameterized by a type that is derived from BasePage<T>
.
To infer why, you have to look at how the type parameter T
is actually used.
After some digging, as you move up the inheritance chain, you'll come up upon this class:
(github)
public class GenericPage<T> : PageBase where T : GenericPage<T>
public bool IsStartPage
get return !ParentId.HasValue && SortOrder == 0;
public GenericPage() : base()
public static T Create(IApi api, string typeId = null)
return api.Pages.Create<T>(typeId);
As far as I can see, the only purpose for the generic constraint is to make sure that the Create
method returns the least abstract type possible.
Not sure if it's worth it, though, but perhaps there's some good reason behind it, or it could be only for convenience, or maybe there's no too much substance behind it and it's just an overly elaborate way to avoid a cast (BTW, I'm not implying that is the case here, I'm just saying that people do that sometimes).
Note that this doesn't allow them to avoid reflection - the api.Pages
is a repository of pages that obtains typeof(T).Name
, and passes it as the typeId
to the contentService.Create
method (see here).
add a comment |Â
up vote
5
down vote
accepted
Can some help me understand why the class is inheriting from a base of same type?
It's not, it's inheriting from Page<T>
, but T
itself is constrained to be parameterized by a type that is derived from BasePage<T>
.
To infer why, you have to look at how the type parameter T
is actually used.
After some digging, as you move up the inheritance chain, you'll come up upon this class:
(github)
public class GenericPage<T> : PageBase where T : GenericPage<T>
public bool IsStartPage
get return !ParentId.HasValue && SortOrder == 0;
public GenericPage() : base()
public static T Create(IApi api, string typeId = null)
return api.Pages.Create<T>(typeId);
As far as I can see, the only purpose for the generic constraint is to make sure that the Create
method returns the least abstract type possible.
Not sure if it's worth it, though, but perhaps there's some good reason behind it, or it could be only for convenience, or maybe there's no too much substance behind it and it's just an overly elaborate way to avoid a cast (BTW, I'm not implying that is the case here, I'm just saying that people do that sometimes).
Note that this doesn't allow them to avoid reflection - the api.Pages
is a repository of pages that obtains typeof(T).Name
, and passes it as the typeId
to the contentService.Create
method (see here).
add a comment |Â
up vote
5
down vote
accepted
up vote
5
down vote
accepted
Can some help me understand why the class is inheriting from a base of same type?
It's not, it's inheriting from Page<T>
, but T
itself is constrained to be parameterized by a type that is derived from BasePage<T>
.
To infer why, you have to look at how the type parameter T
is actually used.
After some digging, as you move up the inheritance chain, you'll come up upon this class:
(github)
public class GenericPage<T> : PageBase where T : GenericPage<T>
public bool IsStartPage
get return !ParentId.HasValue && SortOrder == 0;
public GenericPage() : base()
public static T Create(IApi api, string typeId = null)
return api.Pages.Create<T>(typeId);
As far as I can see, the only purpose for the generic constraint is to make sure that the Create
method returns the least abstract type possible.
Not sure if it's worth it, though, but perhaps there's some good reason behind it, or it could be only for convenience, or maybe there's no too much substance behind it and it's just an overly elaborate way to avoid a cast (BTW, I'm not implying that is the case here, I'm just saying that people do that sometimes).
Note that this doesn't allow them to avoid reflection - the api.Pages
is a repository of pages that obtains typeof(T).Name
, and passes it as the typeId
to the contentService.Create
method (see here).
Can some help me understand why the class is inheriting from a base of same type?
It's not, it's inheriting from Page<T>
, but T
itself is constrained to be parameterized by a type that is derived from BasePage<T>
.
To infer why, you have to look at how the type parameter T
is actually used.
After some digging, as you move up the inheritance chain, you'll come up upon this class:
(github)
public class GenericPage<T> : PageBase where T : GenericPage<T>
public bool IsStartPage
get return !ParentId.HasValue && SortOrder == 0;
public GenericPage() : base()
public static T Create(IApi api, string typeId = null)
return api.Pages.Create<T>(typeId);
As far as I can see, the only purpose for the generic constraint is to make sure that the Create
method returns the least abstract type possible.
Not sure if it's worth it, though, but perhaps there's some good reason behind it, or it could be only for convenience, or maybe there's no too much substance behind it and it's just an overly elaborate way to avoid a cast (BTW, I'm not implying that is the case here, I'm just saying that people do that sometimes).
Note that this doesn't allow them to avoid reflection - the api.Pages
is a repository of pages that obtains typeof(T).Name
, and passes it as the typeId
to the contentService.Create
method (see here).
answered 3 hours ago
Filip MilovanoviÃÂ
1,16318
1,16318
add a comment |Â
add a comment |Â
up vote
0
down vote
One common use of this is related to the concept of self-types: a type parameter that resolves to the current type. Let's say you want to define an interface with a clone()
method. The clone()
method must always return an instance of the class on which it was called. How do you declare that method? In a generics system that has self-types, it's easy. You just say it returns self
. So if I have a class Foo
, the clone method must be declared to return Foo
. In Java and (from a cursory search) C#, this isn't an option. You instead see declarations like what you see in this class. It's important to understand that this is not the same thing as a self-type and the restrictions it provides are weaker. If you have a Foo
and a Bar
class that both derive from BasePage
, you can (if I am not mistaken) define Foo to be parameterized by Bar
. That might be useful but I think typically, most of the time, this will be used like a self-type and it's just understood that even though you can goof around and substitute with other types, it's not something you should do. I played around with this idea long ago but came to the conclusion that it wasn't worth the effort because the limitations of Java generics. C# generics are of course more fully featured but it seems to have this same limitation.
The other time this approach get's used it when you are building graph-like types such as trees or other recursive structures. The declaration allows types to meet the requirements of Page but further refine the type. You might see this in a tree structure. For example a Node
might be parameterized by Node
to allow for implementations to define that they aren't just Trees containing any type of Node but a specific sub-type of Node (usually their own type.) I think that's more of what's going on here.
add a comment |Â
up vote
0
down vote
One common use of this is related to the concept of self-types: a type parameter that resolves to the current type. Let's say you want to define an interface with a clone()
method. The clone()
method must always return an instance of the class on which it was called. How do you declare that method? In a generics system that has self-types, it's easy. You just say it returns self
. So if I have a class Foo
, the clone method must be declared to return Foo
. In Java and (from a cursory search) C#, this isn't an option. You instead see declarations like what you see in this class. It's important to understand that this is not the same thing as a self-type and the restrictions it provides are weaker. If you have a Foo
and a Bar
class that both derive from BasePage
, you can (if I am not mistaken) define Foo to be parameterized by Bar
. That might be useful but I think typically, most of the time, this will be used like a self-type and it's just understood that even though you can goof around and substitute with other types, it's not something you should do. I played around with this idea long ago but came to the conclusion that it wasn't worth the effort because the limitations of Java generics. C# generics are of course more fully featured but it seems to have this same limitation.
The other time this approach get's used it when you are building graph-like types such as trees or other recursive structures. The declaration allows types to meet the requirements of Page but further refine the type. You might see this in a tree structure. For example a Node
might be parameterized by Node
to allow for implementations to define that they aren't just Trees containing any type of Node but a specific sub-type of Node (usually their own type.) I think that's more of what's going on here.
add a comment |Â
up vote
0
down vote
up vote
0
down vote
One common use of this is related to the concept of self-types: a type parameter that resolves to the current type. Let's say you want to define an interface with a clone()
method. The clone()
method must always return an instance of the class on which it was called. How do you declare that method? In a generics system that has self-types, it's easy. You just say it returns self
. So if I have a class Foo
, the clone method must be declared to return Foo
. In Java and (from a cursory search) C#, this isn't an option. You instead see declarations like what you see in this class. It's important to understand that this is not the same thing as a self-type and the restrictions it provides are weaker. If you have a Foo
and a Bar
class that both derive from BasePage
, you can (if I am not mistaken) define Foo to be parameterized by Bar
. That might be useful but I think typically, most of the time, this will be used like a self-type and it's just understood that even though you can goof around and substitute with other types, it's not something you should do. I played around with this idea long ago but came to the conclusion that it wasn't worth the effort because the limitations of Java generics. C# generics are of course more fully featured but it seems to have this same limitation.
The other time this approach get's used it when you are building graph-like types such as trees or other recursive structures. The declaration allows types to meet the requirements of Page but further refine the type. You might see this in a tree structure. For example a Node
might be parameterized by Node
to allow for implementations to define that they aren't just Trees containing any type of Node but a specific sub-type of Node (usually their own type.) I think that's more of what's going on here.
One common use of this is related to the concept of self-types: a type parameter that resolves to the current type. Let's say you want to define an interface with a clone()
method. The clone()
method must always return an instance of the class on which it was called. How do you declare that method? In a generics system that has self-types, it's easy. You just say it returns self
. So if I have a class Foo
, the clone method must be declared to return Foo
. In Java and (from a cursory search) C#, this isn't an option. You instead see declarations like what you see in this class. It's important to understand that this is not the same thing as a self-type and the restrictions it provides are weaker. If you have a Foo
and a Bar
class that both derive from BasePage
, you can (if I am not mistaken) define Foo to be parameterized by Bar
. That might be useful but I think typically, most of the time, this will be used like a self-type and it's just understood that even though you can goof around and substitute with other types, it's not something you should do. I played around with this idea long ago but came to the conclusion that it wasn't worth the effort because the limitations of Java generics. C# generics are of course more fully featured but it seems to have this same limitation.
The other time this approach get's used it when you are building graph-like types such as trees or other recursive structures. The declaration allows types to meet the requirements of Page but further refine the type. You might see this in a tree structure. For example a Node
might be parameterized by Node
to allow for implementations to define that they aren't just Trees containing any type of Node but a specific sub-type of Node (usually their own type.) I think that's more of what's going on here.
answered 2 hours ago
JimmyJames
12.1k1947
12.1k1947
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f380874%2fnet-self-reference%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
5
blogs.msdn.microsoft.com/ericlippert/2011/02/03/â¦
â David Arno
4 hours ago
4
Despite the downvotes and close votes, I think the community got it wrong on this one. This is a clearly-stated question having to do with a specific and non-trivial design decision, the very essence of what this site is about.
â Robert Harvey
4 hours ago
1
@RobertHarvey: could not agree more, but I guess we will not be able to educate persons like gnat on this ;-) And he is obviously not the only one who mistakenly believes any question with some code in it need to be closed.
â Doc Brown
3 hours ago
Just hang around and reopen it when it gets closed.
â David Arno
3 hours ago