C#慢慢学 (二)(e文转)

1.14 Properties
A property is a named attribute associated with an object or a class. Examples of properties include the length of a string, the size of a font, the caption of a window, the name of a customer, and so on. Properties are a natural extension of fields – both are named members with associated types, and the syntax for accessing fields and properties is the same. However, unlike fields, properties do not denote storage locations. Instead, properties have accessors that specify the statements to execute in order to read or write their values. Properties thus provide a mechanism for associating actions with the reading and writing of an object’s attributes, and they furthermore permit such attributes to be computed.
The success of rapid application development tools like Visual Basic can, to some extent, be attributed to the inclusion of properties as a first-class element. VB developers can think of a property as being field-like, and this allows them to focus on their own application logic rather than on the details of a component they happen to be using. On the face of it, this difference might not seem like a big deal, but modern component-oriented programs tend to be chockfull of property reads and writes. Languages with method-like usage of properties (e.g., o.SetValue(o.GetValue() + 1);) are clearly at a disadvantage compared to languages that feature field-like usage  of properties (e.g., o.Value++;).
Properties are defined in C# using property declaration syntax. The first part of the syntax looks quite similar to a field declaration. The second part includes a get accessor and/or a set accessor. In the example below, the Button class defines a Caption property.
public class Button: Control
{
    private string caption;
    public string Caption {
        get {
            return caption;
        }
        set {
            caption = value;
            Repaint();
        }
    }
}
Properties that can be both read and written, like the Caption property, include both get and set accessors. The get accessor is called when the property’s value is read; the set accessor is called when the property’s value is written. In a set accessor; the new value for the property is given in an implicit value parameter.
Declaration of properties is relatively straightforward, but the true value of properties shows itself is in their usage rather than in their declaration. The Caption property can read and written in the same way that fields can be read and written:
Button b = new Button();
b.Caption = "ABC";        // set
string s = b.Caption;    // get
b.Caption += "DEF”;        // get & set
1.15 Indexers
If properties in C# can be likened to “smart fields”, then indexers can be likened to “smart arrays”. Whereas properties enable field-like access, indexers enable array-like access.
As an example, consider a ListBox control, which displays strings. This class wants to expose an array-like data structure that exposes the list of strings it contains, but also wants to be able to automatically update its contents when a value is altered. These goals can be accomplished by providing an indexer. The syntax for an indexer declaration is similar to that of a property declaration, with the main differences being that indexers are nameless (the “name” used in the declaration is this, since this is being indexed) and that additional indexing parameters are provided between square brackets.
public class ListBox: Control
{
    private string[] items;
    public string this[int index] {
        get {
            return items[index];
        }
        set {
            items[index] = value;
            Repaint();
        }
    }
}
As with properties, the convenience of indexers is best shown by looking at use rather than declaration. The ListBox class can be used as follows:
ListBox listBox = ...;
listBox[0] = "hello";
Console.WriteLine(listBox[0]);
1.16 Events
Events permit a class to declare notifications for which clients can attach executable code in the form of event handlers. Events are an important aspect of the design of class libraries in general, and of the system-provided class library in particular. C# provides an integrated solution for events.
A class defines an event by providing an event declaration, which looks quite similar to a field or event declaration but with an added event keyword. The type of this declaration must be a delegate type. In the example below, the Button class defines a Click event of type EventHandler.
public delegate void EventHandler(object sender, Event e);
public class Button: Control
{
    public event EventHandler Click;
    public void Reset() {
        Click = null;
    }
}
Inside the Button class, the Click member can be corresponds exactly to a private field of type EventHandler. However, outside the Button class, the Click member can only be used on the left hand side of the += and -= operators. This restricts client code to adding or removing an event handler. In the client code example below, the Form1 class adds Button1_Click as an event handler for Button1’s Click event. In the Disconnect method, the event handler is removed.
using System;
public class Form1: Form
{
    public Form1() {
        // Add Button1_Click as an event handler for Button1’s Click event
        Button1.Click += new EventHandler(Button1_Click);
    }
    Button Button1 = new Button();
    void Button1_Click(object sender, Event e) {
        Console.WriteLine("Button1 was clicked!");
    }
    public void Disconnect() {
        Button1.Click -= new EventHandler(Button1_Click);
    }
}
The Button class could be rewritten to use a property-like event declaration rather than a field-like event declaration. This change has no effect on client code.
public class Button: Control
{
        public event EventHandler Click {
            get {...}
            set {...}
        }
        public void Reset() {
            Click = null;
        }
}
1.17 Versioning
Versioning is an after-thought in most languages, but not in C#.
“Versioning” actually has two different meanings. A new version of a component is “source compatible” with a previous version if code that depends on the previous version can, when recompiled, work with the new version. In contrast, for a “binary compatible” component, a program that depended on the old version can, without recompilation, work with the new version.
Most languages do not support binary compatibility at all, and many do little to facilitate source compatibility. In fact, some languages contain flaws that make it impossible, in general, to evolve a class over time without breaking some client code.
As an example, consider the situation of a base class author who ships a class named Base. In this first version, Base contains no F method. A component named Derived derives from Base, and introduces an F. This Derived class, along with the class Base that it depends on, is released to customers, who deploy to numerous clients and servers.
// Author A
namespace A
{
    class Base    // version 1
    {
    }
}
// Author B
namespace B
{
    class Derived: A.Base
    {
        public virtual void F() {
            System.Console.WriteLine("Derived.F");
        }
    }
}
So far, so good. But now the versioning trouble begins. The author of Base produces a new version, and adds its own F method.
// Author A
namespace A
{
    class Base    // version 2
    {
        public virtual void F() {        // added in version 2
            System.Console.WriteLine("Base.F");
        }
    }
}
This new version of Base should be both source and binary compatible with the initial version. (If it weren’t possible to simply add a method then a base class could never evolve.)  Unfortunately, the new F in Base makes the meaning of Derived’s F is unclear. Did Derived mean to override Base’s F?  This seems unlikely, since when Derived was compiled, Base did not even have an F!  Further, if Derived’s F does override Base’s F, then does Derived’s F adhere to the contract specified by Base?  This seems even more unlikely, since it is pretty darn difficult for Derived’s F to adhere to a contract that didn’t exist when it was written. For example, the contract of Base’s F might require that overrides of it always call the base. Derived’s F could not possibly adhere to such a contract since it cannot call a method that does not yet exist.
In practice, will name collisions of this kind actually occur?  Let’s consider the factors involved. First, it is important to note that the authors are working completely independently – possibly in separate corporations – so no collaboration is possible. Second, there may be many derived classes. If there are more derived classes, then name collisions are more likely to occur. Imagine that the base class is Form, and that all VB, VC++ and C# developers are creating derived classes – that’s a lot of derived classes. Finally, name collisions are more likely if the base class is in a specific domain, as authors of both a base class and its derived classes are likely to choose names from this domain.
C# addresses this versioning problem by requiring developers to clearly state their intent. In the original code example, the code was clear, since Base did not even have an F. Clearly, Derived’s F is intended as a new method rather than an override of a base method, since no base method named F exists.
// Author A
namespace A
{
    class Base
    {
    }
}
// Author B
namespace B
{
    class Derived: A.Base
    {
        public virtual void F() {
            System.Console.WriteLine("Derived.F");
        }
    }
}
If Base adds an F and ships a new version, then the intent of a binary version of Derived is still clear – Derived’s F is semantically unrelated, and should not be treated as an override.
However, when Derived is recompiled, the meaning is unclear – the author of Derived may intend its F to override Base’s F, or to hide it. Since the intent is unclear, the C# compiler produces a warning, and by default makes Derived’s F hide Base’s F – duplicating the semantics for the case in which Derived is not recompiled. This warning alerts Derived’s author to the presence of the F method in Base. If Derived’s F is semantically unrelated to Base’s F, then Derived’s author can express this intent – and, in effect, turn off the warning – by using the new keyword in the declaration of F.
// Author A
namespace A
{
    class Base                    // version 2
    {
        public virtual void F() { // added in version 2
            System.Console.WriteLine("Base.F");
        }
    }
}
// Author B
namespace B
{
    class Derived: A.Base    // version 2a: new
    {
        new public virtual void F() {
            System.Console.WriteLine("Derived.F");
        }
    }
}
On the other hand, Derived’s author might investigate further, and decide that Derived’s F should override Base’s F, and clearly specify this intent through specification of the override keyword, as shown below.
// Author A
namespace A
{
    class Base                    // version 2
    {
        public virtual void F() { // added in version 2
            System.Console.WriteLine("Base.F");
        }
    }
}
// Author B
namespace B
{
    class Derived: A.Base    // version 2b: override
    {
        public override void F() {
            base.F();
            System.Console.WriteLine("Derived.F");
        }
    }
}
The author of Derived has one other option, and that is to change the name of F, thus completely avoiding the name collision. Though this change would break source and binary compatibility for Derived, the importance of this compatibility varies depending on the scenario. If Derived is not exposed to other programs, then changing the name of F is likely a good idea, as it would improve the readability of the program – there would no longer be any confusion about the meaning of F.
1.18 Attributes
C# is a procedural language, but like all procedural languages it does have some declarative elements. For example, the accessibility of a method in a class is specified by decorating it public, protected, internal, protected internal, or private. Through its support for attributes, C# generalizes this capability, so that programmers can invent new kinds of declarative information, specify this declarative information for various program entities, and retrieve this declarative information at run-time. Programs specify this additional declarative information by defining and using attributes.
For instance, a framework might define a HelpAttribute attribute that can be placed on program elements such as classes and methods to provide a mapping from program elements to documentation for them. The example
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute: System.Attribute
{
    public HelpAttribute(string url) {
        this.url = url;
    }
    public string Topic = null;
    private string url;
    public string Url {
        get { return url; }
    }
}
defines an attribute class named HelpAttribute, or Help for short, that has one positional parameter (string url) and one named argument (string Topic). Positional parameters are defined by the formal parameters for public constructors of the attribute class; named parameters are defined by public read-write properties of the attribute class. The square brackets in the example indicate the use of an attribute in defining the Help attribute. In this case, the AttributeUsage attribute indicates that any program element can be decorated with the Help attribute.
The example
[Help("http://www.mycompany.com/…/Class1.htm")]
public class Class1
{
    [Help("http://www.mycompany.com/…/Class1.htm", Topic ="F")]
    public void F() {}
}
shows several uses of the attribute.
Attribute information for a given program element can be retrieved at run-time by using the .NET runtime’s reflection support. The example
using System;
class Test
{
    static void Main() {
        Type type = typeof(Class1);
        object[] arr = type.GetCustomAttributes(typeof(HelpAttribute));
        if (arr.Length == 0)
            Console.WriteLine("Class1 has no Help attribute.");
        else {
            HelpAttribute ha = (HelpAttribute) arr[0];
            Console.WriteLine("Url = {0}, Topic = {1}", ha.Url, ha.Topic);
        }
    }
}
checks to see if Class1 has a Help attribute, and writes out the associated Topic and Url values if the attribute is present.

时间: 2024-10-30 14:13:28

C#慢慢学 (二)(e文转)的相关文章

C#慢慢学 (一)(e文转)

C# is a simple, modern, object oriented, and type-safe programming language derived from C and C++. C# (pronounced "C sharp") is firmly planted in the C and C++ family tree of languages, and will immediately be familiar to C and C++ programmers.

站长原创文章二三事(二) 软文需要“区别对待”

中介交易 SEO诊断 淘宝客 云主机 技术大厅 在之前的文章站长原创文章二三事(一):以正确的态度看待原创中讲到了原创文章对于站长的重要性.站长写作原创文章可谓乐此不疲,除了分享经验交流学习外,原创文章另外一个重要的作用就是软文.也可以说站长的原创文章大都是软文性质.相比较为直接的硬性广告,首先,软文的投入成本较低.现在即便最小的广告投入,也要动辄几百上千一个月.个人站长大多处于创业时期难以筹集更多的资金用于广告投入.而软文无需花费一般站长难以承受的高昂广告费用.其次,软文可发布在博客.论坛.门

慢慢学-初学者关于指针的一个问题

问题描述 初学者关于指针的一个问题 void union(Linklist& la,Linklist&lb,Linklist&lc){ pa = la ->next;pb = lb->next; lc=pc=la; lc->next = NULL; ....... } 其中lc=pc=la; lc->next = NULL;怎么理解,la的值赋给lc就是指针lc指向头结点la,那lc 的指针域是空怎么理解呢? 解决方案 lc 有自己的内存空间,lc=la;l

好吧,就算没有什么很出色的,但可是我慢慢学过来的

书中的内容很硬啊. 慢慢理解了很多电商的编码及构架原因. 自我欣赏.

阿里巴巴做手游 还要慢慢学

阿里巴巴本周宣布全平台投入手机游戏,并且拿出70%的利润与开发者共同分成,各种分析一致认为这是马云在抄马化腾的后路.事实上,拨开市场各种分析.猜测,游戏开发者又是如何看待阿里做手游这件事情?我们通过走访发现,很多游戏开发者对阿里做手游平台这事不怎么关注,有的则直说阿里不会改变现有手游格局,初期只能吸引小CP(注:指手机游戏开发者)入驻,知名的开发商还是以观望为主.有人说在中国互联网混,BAT是万万不能得罪的,其实从今年的发展速度来看,这个规律已经延续到了游戏圈,现在百度手里有91,腾讯手里有QQ

急,大二用Java能搞什么立项?学校内的。

问题描述 我现在学Java,学校有提供经费给有想法的大学生.比如用java做个什么手机游戏,做个系统之类的.但这些已被别人做过多次了.大家有给点创新点的立项吗,谢谢!!! 解决方案 解决方案二:给你们学校做个实用的系统解决方案三:做过了不一定就不能再做了,如果你能做到更好,那干嘛不做呢?解决方案四:引用2楼renjianguokeivor的回复: 做过了不一定就不能再做了,如果你能做到更好,那干嘛不做呢? 做个2期系统,优化添加功能....解决方案五:做一个实用的系统,而不是花架子解决方案六:可

java入门的困惑,到底怎么学些java?

问题描述 以前一直觉得java开发比起c,c++,有一点low.这两年u随着大数据的兴起,感觉java越来越吃香,Apache大数据生态圈,很多开元项目都是java写的.出于工作需要,不得不接触到java,longlongago,有一点c++编程经验,但是学起java感觉很吃力.基础的一些democode倒是很容易看懂,一接触到大量代码,一个文件中各种类,一个类中又套着N多类,看着看着就晕了.平时工作很忙,也没有时间从头扎扎实实的学起,感觉达到看源码的水平,很难啊..请教各位同学,java到底要

90后站长:建站50天 让我学到的

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 今天看统计的时候无意中看到统计时间已经是50天了,时间过的真快,马上就两个月了.可是看看自己的小站,每天十几的ip,真是惭愧.但是好好想想,和50天之前相比,呵呵,也算是有点收获吧!做站前和做站后的想法是完全不同的.下面谈谈个人从接触网络到建站50天的一些经历吧!(没有什么价值,纯粹是个人经历). 接触网络是在上初中那会,大概03 04年吧!

【Python数据挖掘课程】二.Kmeans聚类数据分析及Anaconda介绍

        这次课程主要讲述一个关于Kmeans聚类的数据分析案例,通过这个案例让同学们简单了解大数据分析的基本流程,以及使用Python实现相关的聚类分析.         主要内容包括:         1.Anaconda软件的安装过程及简单配置         2.聚类及Kmeans算法介绍        3.案例分析:Kmeans实现运动员位置聚集         前文推荐:[Python数据挖掘课程]一.安装Python及爬虫入门介绍         希望这篇文章对你有所帮助,尤