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. c++调用python函数时,使用PyArray_SimpleNewFromData(nd, dims, typenum, data)函数时出现内存错误的问题

    示例程序: int main(int argc, char *argv[]){ PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pArgs,* ...

  2. pandas 读取文件

    import pandas as pd import matplotlib.pyplot as plt data = pd.read_csv('G:timeCompare.txt', sep=' ', ...

  3. jupyter 修改工作路径

    在所需打开的目录中新建一个runJupyter.bat文件 将内容修改为: cd ......jupyter notebook 注1:上述两行中,第一行的......为路径(可以不添加,可空着不填), ...

  4. 1.1_php基础语法

    一,变量与常量: 二,php中的运算符(字符串拼接): 三,php数组. <!DOCTYPE html> <html> <head> <meta charse ...

  5. HDU 1863 畅通工程(Kruskal)

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

  6. mysql中修改字段的类型

    修改表字段的类型: ALTER TABLE 表名  MODIFY COLUMN 字段名 字段类型定义 如:将movie_mark修改为浮点型 alter table new_playing_video ...

  7. Spring Context及ApplicationContext

    web.xml 这是声明了一个父工厂 <context-param> <param-name>contextConfigLocation</param-name> ...

  8. iOS接收远程通知响应方法

    点击 iOS 接收远程推送主要牵扯到的方法有以下五种 (1) - (BOOL)application:(UIApplication *)application didFinishLaunchingWi ...

  9. java 常用的几个配置

    1.保存代码格式化,打勾即可 2.如何让eclipse像vs那样自动提示,在打勾的地方加入 abcdefghijklmnopqrstuvwxyz.即可

  10. https://github.com/arut/nginx-rtmp-module.git

    https://github.com/arut/nginx-rtmp-module.git NGINX-based Media Streaming Server nginx-rtmp-module P ...