Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C-sharp language specification.2004.pdf
Скачиваний:
14
Добавлен:
23.08.2013
Размер:
2.55 Mб
Скачать

C# LANGUAGE SPECIFICATION

18.13 Versioning

2Versioning is the process of evolving a component over time in a compatible manner. A new version of a

3component is source compatible with a previous version if code that depends on the previous version can,

4when recompiled, work with the new version. In contrast, a new version of a component is binary

5compatible if an application that depended on the old version can, without recompilation, work with the new

6version.

7Most languages do not support binary compatibility at all, and many do little to facilitate source

8compatibility. In fact, some languages contain flaws that make it impossible, in general, to evolve a class

9over time without breaking at least some client code.

10As an example, consider the situation of a base class author who ships a class named Base. In the first

11version, Base contains no method F. A component named Derived derives from Base, and introduces

12an F. This Derived class, along with the class Base on which it depends, is released to customers, who

13deploy to numerous clients and servers.

14// Author A

15namespace A

16{

17

public class Base

// version 1

18

{

 

19}

20}

21// Author B

22namespace B

23{

24

class Derived: A.Base

25

{

26

public virtual void F() {

27

System.Console.WriteLine("Derived.F");

28

}

29}

30}

31So far, so good, but now the versioning trouble begins. The author of Base produces a new version, giving it

32its own method F.

33// Author A

34namespace A

35{

36

public class Base

// version 2

37

{

 

 

38

public virtual void F() {

// added in version 2

39

System.Console.WriteLine("Base.F");

40

}

 

 

41}

42}

43This new version of Base should be both source and binary compatible with the initial version. (If it weren’t

44possible to simply add a method then a base class could never evolve.) Unfortunately, the new F in Base

45makes the meaning of Derived’s F unclear. Did Derived mean to override Base’s F? This seems unlikely,

46since when Derived was compiled, Base did not even have an F! Further, if Derived’s F does override

47Base’s F, then it shall adhere to the contract specified by Base—a contract that was unspecified when

48Derived was written. In some cases, this is impossible. For example, Base’s F might require that overrides

49of it always call the base. Derived’s F could not possibly adhere to such a contract.

50C# addresses this versioning problem by requiring developers to state their intent clearly. In the original

51code example, the code was clear, since Base did not even have an F. Clearly, Derived’s F is intended as a

52new method rather than an override of a base method, since no base method named F exists.

53If Base adds an F and ships a new version, then the intent of a binary version of Derived is still clear—

54Derived’s F is semantically unrelated, and should not be treated as an override.

48

Chapter 8 Language overview

1However, when Derived is recompiled, the meaning is unclear—the author of Derived might intend its F

2to override Base’s F, or to hide it. Since the intent is unclear, the compiler produces a warning, and by

3default makes Derived’s F hide Base’s F. This course of action duplicates the semantics for the case in

4which Derived is not recompiled. The warning that is generated alerts Derived’s author to the presence of

5the F method in Base.

6If Derived’s F is semantically unrelated to Base’s F, then Derived’s author can express this intent—and,

7in effect, turn off the warning—by using the new keyword in the declaration of F.

8// Author A

9namespace A

10{

11

public class Base

// version 2

12

{

 

13

public virtual void F() { // added in version 2

14

System.Console.WriteLine("Base.F");

15

}

 

16}

17}

18// Author B

19namespace B

20{

21

class Derived: A.Base // version 2a: new

22

{

23

new public virtual void F() {

24

System.Console.WriteLine("Derived.F");

25

}

26}

27}

28On the other hand, Derived’s author might investigate further, and decide that Derived’s F should

29override Base’s F. This intent can be specified by using the override keyword, as shown below.

30// Author A

31namespace A

32{

33

public class Base

// version 2

34

{

 

35

public virtual void F() { // added in version 2

36

System.Console.WriteLine("Base.F");

37

}

 

38}

39}

40// Author B

41namespace B

42{

43

class Derived: A.Base // version 2b: override

44

{

45

public override void F() {

46

base.F();

47

System.Console.WriteLine("Derived.F");

48

}

49}

50}

51The author of Derived has one other option, and that is to change the name of F, thus completely avoiding

52the name collision. Although this change would break source and binary compatibility for Derived, the

53importance of this compatibility varies depending on the scenario. If Derived is not exposed to other

54programs, then changing the name of F is likely a good idea, as it would improve the readability of the

55program—there would no longer be any confusion about the meaning of F.

568.14 Extern Aliases

57By default types from all referenced assemblies and the current program are placed into a single namespace

58hierarchy. With only a single namespace hierarchy, it is not possible to reference types with the same fully

49

C# LANGUAGE SPECIFICATION

1qualified name from different assemblies, a situation that arises when types are independently given the

2same name, or when a program needs to reference several versions of the same assembly. Extern aliases

3make it possible to create and reference separate namespace hierarchies in such situations.

4Consider the following two assemblies:

5Assembly a1.dll:

6namespace N

7{

8

public class A {}

9public class B {}

10}

11Assembly a2.dll:

12namespace N

13{

14

public class B {}

15public class C {}

16}

17and the following program:

18class Test

19{

20

N.A a;

// Ok

21

N.B b;

// Error

22

N.C c;

// Ok

23}

24A command-line compiler might allow compilation of this program with a command-line something like

25this:

26csc /r:a1.dll /r:a2.dll test.cs

27where the types contained in a1.dll and a2.dll are all placed in the global namespace hierarchy, and an

28error occurs because the type N.B exists in both assemblies. With extern aliases, it becomes possible to place

29the types contained in a1.dll and a2.dll into separate namespace hierarchies.

30The following program declares and uses two extern aliases, X and Y, each of which represent the root of a

31distinct namespace hierarchy created from the types contained in one or more assemblies.

32extern alias X;

33extern alias Y;

34class Test

35{

36

X::N.A a;

37

X::N.B b1;

38

Y::N.B b2;

39Y::N.C c;

40}

41The program declares the existence of the extern aliases X and Y, but the actual definitions of the aliases are

42external to the program. A command line compiler can enable the definition of the extern aliases X and Y

43such that the extern alias X is the root of a namespace hierarchy formed by the types in a1.dll and Y is the

44root of a namespace hierarchy formed by the types in a2.dll. A compiler might enable the above example

45with a command-line like:

46csc /r:X=a1.dll /r:Y=a2.dll test.cs

47The identically named N.B classes can now be referenced as X.N.B and Y.N.B, or, using the namespace

48alias qualifier, X::N.B and Y::N.B. An error occurs if a program declares an extern alias for which no

49external definition is provided.

50An extern alias can include multiple assemblies, and a particular assembly can be included in multiple extern

51aliases. For example, given the assembly

50

Chapter 8 Language overview

1Assembly a3.dll:

2namespace N

3{

4

public class D {}

5public class E {}

6}

7a command line like

8csc /r:X=a1.dll /r:X=a3.dll /r:Y=a2.dll /r:Y=a3.dll test.cs

9might define the extern alias X to be the root of a namespace hierarchy formed by the types in a1.dll and

10a3.dll and Y to be the root of a namespace hierarchy formed by the types in a2.dll and a3.dll. Because

11of this definition, it is possible to refer to the class N.D in a3.dll as both X::N.D and Y::N.D.

12An assembly can be placed in the global namespace hierarchy even if it is also included in one or more

13extern aliases. For example, the command line

14csc /r:a1.dll /r:X=a1.dll /r:Y=a2.dll test.cs

15places the assembly a1.dll in both the global namespace hierarchy and the namespace hierarchy rooted by

16the extern alias X. Consequently, the class N.A can be referred to as N.A or X::N.A.

17It is possible to ensure that a lookup always starts at the root of the global namespace hierarchy by using the

18identifier global with the namespace alias qualifier, such as global::System.IO.Stream.

19A using directive may reference an extern alias that was defined in the same immediately enclosing

20namespace declaration or compilation unit. For example:

21extern alias X;

22using X::N;

23class Test

24{

25

A

a;

//

X::N.A

26

B

b;

//

X::N.B

27}

288.15 Attributes

29C# is an imperative language, but like all imperative languages it does have some declarative elements. For

30example, the accessibility of a method in a class is specified by declaring it public, protected,

31internal, protected internal, or private. C# generalizes this capability, so that programmers can

32invent new kinds of declarative information, attach this declarative information to various program entities,

33and retrieve this declarative information at run-time. Programs specify this additional declarative

34information by defining and using attributes (§24).

35For instance, a framework might define a HelpAttribute attribute that can be placed on program elements

36such as classes and methods, enabling developers to provide a mapping from program elements to

37documentation for them. The example

38using System;

39[AttributeUsage(AttributeTargets.All)]

40public class HelpAttribute: Attribute

41{

42

public HelpAttribute(string url) {

43

this.url = url;

44

}

45

public string Topic = null;

46

private string url;

47

public string Url {

48

get { return url; }

49}

50}

51

Соседние файлы в предмете Электротехника