Define class with itself as generic implementation. Why/how does this work?

问题:

I've normally been creating Prism Events used by the EventAggregator like:

public class SomeEvent : CompositePresentationEvent<SomeEventArgs> { }

public class SomeEventArgs
{
public string Name { get; set; }
}

But while looking at a co-workers code I noticed they did:

public class SomeEvent : CompositePresentationEvent<SomeEvent>
{
public string Name { get; set; }
}

I guess my first question is why does this even compile? It seems to me that it's implementing a class that isn't defined yet. And second, does it negatively affect the application at all, is it negligible, or better?

解答:

I guess my first question is why does this even compile?

Which rule in the spec do you believe it's violating?   没有违反编译的规则

It seems to me that it's implementing a class that isn't defined yet.

I think you'd have to specify the exact meaning of each of those terms for the statement to be judged as accurate or not. The compiler knows about CompositePresentationEvent as it's declared elsewhere (presumably) and it knows about SomeEvent because that's the class being declared. It's like having a field of type Foo within a class Foo - entirely valid.

It's also very useful to be able to do this - particularly for comparisons. For example:

public sealed class Foo : IComparable<Foo>

says that any instance of class Foo knows how to compare itself with another instance, so it can be used for sorting in a type-safe way. In the case of structs, this also allows you to reduce boxing, as calling x.CompareTo(y) won't need any boxing when x is known to be of a type which implements IComparable<> appropriately.

Note that types can get far more interestingly and confusingly recursive. Take this (slightly modified) example from my port of Protocol Buffers:

public interface IMessage<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder> public interface IBuilder<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>

Here, the aim is to basically end up with two types - a "message" and a "builder" so that you can always construct each from the other. For example:

public class Foo : IMessage<Foo, FooBuilder>
{
...
} public class FooBuilder : IBuilder<Foo, FooBuilder>
{
...
}

Curiously recurring template pattern

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

Declaring a Class as a Member of itself

回答1

Because it's static and therefore there is only one copy of the variable instance within the AppDomain.

What you're thinking of is this:

public class Foo
{
private Foo lol = new Foo();
}

Notice, everything here is instance, not static.

As the commenters noted (long ago), this is valid syntactically, but would result in a StackOverflowException being thrown, as the assignment requires construction, and construction creates a new assignment. One triggers the other in a cycle that ends when the call stack reaches its maximum length.

In OP's example, assignment requires construction, but the assignment is triggered by the static constructor, not the instance constructor. The static constructor only executes once within an AppDomain, in order to initialize the class' Type. It isn't triggered by instance construction, and so (in OP's example) won't result in a stack overflow.

回答2

This is a software pattern known as "Singleton".  单例就是持有了自己类型的一个静态属性

Some people frown upon the use of the pattern for more reasons than just stated in the question but for better or for worse it is a common pattern in the .NET Framework. You will find Singleton Properties (or fields) on classes that are meant to be instantiated only once. Think of a static Instance property as a global hook upon which to hang an object.

Can a Custom C# object contain a property of the same type as itself?

An object can indeed have a reference to an object of its own type.

This is how most Node type objects are implemented.

As for instantiation - you can pass in the Employee object to use as manager (passing in null for no manager). Constructors can have multiple overloads:

public Employee(Employee manager)
{
this.Manager = manager;
}

Define class with itself as generic implementation. Why/how does this work?的更多相关文章

  1. Why not inherit from List<T>?

    问题: When planning out my programs, I often start with a chain of thought like so: A football team is ...

  2. c++ using Handle Class Pattern to accomplish implementation hiding

    Reference material: Thinking In C++ 2nd eidition chapter 5 section "Handle classes" If the ...

  3. iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总

    --系统应用与系统服务 iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用 ...

  4. iOS--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook等系统服务开发汇总

    iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用系统应用.使用系统服务: ...

  5. Three Sources of a Solid Object-Oriented Design

    pingback :http://java.sys-con.com/node/84633?page=0,1 Object-oriented design is like an alloy consis ...

  6. DbUtils使用例子

    DbUtils: JDBC Utility Component Examples This page provides examples that show how DbUtils may be us ...

  7. iOS开发系列通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开

    --系统应用与系统服务 iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用 ...

  8. 【转】 Build a RESTful Web service using Jersey and Apache Tomcat 2009

    Build a RESTful Web service using Jersey and Apache Tomcat Yi Ming Huang with Dong Fei Wu, Qing GuoP ...

  9. IOS中调用系统的电话、短信、邮件、浏览功能

    iOS开发系列--通讯录.蓝牙.内购.GameCenter.iCloud.Passbook系统服务开发汇总 2015-01-13 09:16 by KenshinCui, 26990 阅读, 35 评 ...

随机推荐

  1. 【BZOJ4503】两个串 FFT

    [BZOJ4503]两个串 Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字 ...

  2. 通过脚本同时运行几个spider

    # 通过脚本同时运行几个spider目录结构: 1.在命令行能通过的情况下创建两个spider如TestSpiderTest2Spider 2.在items.py的同级目录创建run.py文件,有三种 ...

  3. SQL server中使用临时表存储数据

    将查询出来的数据直接用“INTO #临时表名称”的方式完成临时表的创建及数据的插入 SELECT * INTO #temp_NowStatusFROM Test SELECT * FROM #temp ...

  4. When an HTTP server receives a request for a CGI script

    cgicc: Overview of the Common Gateway Interface https://www.gnu.org/software/cgicc/doc/cgi_overview. ...

  5. PHP的几种排序方法

    <?php /** * PHP最常用的四个排序方法及二种查找方法 * 下面的排序方法全部都通过测试 * auther : soulence * date : 2015/06/20 */ //PH ...

  6. django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)

    在python的开发中,遇到了这个错误: django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TA ...

  7. 【人员招聘】岗位职责和技能要求——By Me

  8. Springboot入门-日志框架配置(转载)

    默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台. Logback是log4j框架的作者开发的新一代日志框架,它效率更高.能够适应诸多的运行环境,同时天然支 ...

  9. ceshi1

    图片素材

  10. C/C++中浮点数输出格式问题

    在C语言中,浮点数的输出格式有三种:%g, %f, %e 首先要说的是%e是采用科学计数法来显示. %g与后两者有一个重要的差别,就是设置输出精度的时候,(C中默认浮点输出精度是6),%g认为,包括整 ...