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. 【BZOJ2653】middle 二分+可持久化线段树

    [BZOJ2653]middle Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个 ...

  2. HDU 1232 畅通工程(Kruskal)

    畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  3. maven的核心概念

    1 简单的核心概念 1.1 坐标 groupId.artifactId.version,很简单,这三个坐标定位到了该依赖的位置,有了它们就可以下载该依赖了. 1.2 依赖 如果一个jar包使用了另外一 ...

  4. 【转】Spring中@Component的作用

    今天在写程序的时候看见一个以前没有见过的注解(@Component),在网上查找过后,经过实践,决定把它记录下来. 1.@controller 控制器(注入服务) 用于标注控制层,相当于struts中 ...

  5. python基础之类的封装

    从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,还有alex一起装进麻袋,然后把麻袋封上口子.但其实这种理解相当片面 一 封装什么 你钱包的有多少钱(数据的封装) 你的性取向( ...

  6. 2015-03-10——简析javascript对象

    对于构造函数,它是Function对象的一个实例,可以定义自己的静态成员先实例化出对象,后执行function中内部代码 静态成员:  var abc = function () {};  //既是一 ...

  7. MySQL数据库的设计和表创建

    首先,我们使用Navicat Premium编辑器创建一个用户,同时设置用户权限,MySQL默认有一个root用户,拥有最高权限 下面,我们先创建一个用户: ①CREATE USER  'aaa'@' ...

  8. 请写出用于校验HTML文本框中输入的内容全部为数字的javascript代码

    <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html ...

  9. Drawable.Callback

     一.介绍 public abstract void invalidateDrawable (Drawable who) Called when the drawable needs to be re ...

  10. smtplib与email模块(实现邮件的发送)

    SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件.HTML邮件以及带附件的邮件. Python对SMTP支持有smtplib和email两个模块,email负责构造邮件, ...