饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 48 页

作者:Nick Randolph/等 当前章节:15399 字 更新时间:2026-6-18 14:51

which looks a lot like something out of a dynamic language. The actual query itself, from c

in ..., looks and acts like the declarative language SQL, and the select new { c.ID ...

creates a new anonymous type, again something that looks fairly dynamic. The code-generated

results of these statements are particularly interesting: they’re actually not compiled into classic

IL (intermediate language); they’re instead compiled into what’s called an expression tree and then

interpreted at run time — something that’s taken right out of the dynamic language playbook.

The truth is, these categories don’t particularly matter too much for deciding which tool to use to solve

the right problem. Cross-pollination of feature sets from each category into languages is in fashion

at the moment, which is good for a programmer, whose favorite language typically picks up the best

features from each category. Currently the trend is for imperative/dynamic languages to be used by

application developers, while functional languages have excelled in solving domain-specific problems.

If you’re a .NET programmer, you have even more to smile about. Language interoperation through

the CLS (Common Language Specification) works seamlessly, meaning you can use your favorite

imperative language for the majority of the problems you’re trying to solve, then call into a functional

language for your data manipulation, or maybe some hard-core math you need to solve a problem.

a tale of two lanGuaGes

Since the creation of the .NET Framework there has been an ongoing debate as to which language

developers should use to write their applications. In a lot of cases, teams choose between C# and

VB based upon prior knowledge of either C/C++, Java, or VB6. However, this decision was made

harder by a previous divergence of the languages. In the past, the language teams within Microsoft

made additions to their languages independently, resulting in a number of features appearing in

one language and not the other. For example, VB has integrated language support for working with

XML literals, whereas C# has anonymous methods and iterators. Although these features benefited

a Tale of Two languages .

315

the users of those languages, it made it difficult for organizations to choose which language to use.

In fact, in some cases organizations ended up using a mix of languages attempting to use the best

language for the job at hand. Unfortunately, this either means that the development team needs to

be able to read and write both languages, or the team gets fragmented with some working on the C#

and some on the VB code.

With Visual Studio 2010 and the .NET Framework 4.0, a decision was made within Microsoft to

co-evolve the two primary .NET languages, C# and VB. This co-evolution would seek to minimize

the differences in capabilities between the two languages (often referred to as feature parity).

However, this isn’t an attempt to merge the two languages; in fact, it’s quite the opposite. Microsoft

has clearly indicated that each language may implement a feature in a different way to ensure it is in

line with the way developers already write and interact with the language.

In the coming sections, you learn about the language features that have been added in Visual Studio

2010. You start by looking at the features common to both languages before going through changes

to the individual languages, most of which are discussed in the context of feature parity and how

the introduced feature matches a feature already in the other language.

compiling without Pias

Visual Studio 2010 has first-class support for building both document- and application-level

add-ins for the main Office applications such as Word and Excel. As part of automating these

products, you will want to be able to call into the exposed COM interfaces. You do this by referencing

the Primary Interop Assemblies (PIAs) in order to work with the Microsoft Office Object Model.

In the past, this then introduced a deployment dependency requiring you to ensure that the PIAs not

only existed but were also the version you required. This added unnecessary size and complexity to

the deployment of your add-in.

Both VB and C# include support for deploying applications, whether they be add-ins or standalone

applications that use Office automation, without relying on the users having the PIAs installed on

their machine. In Figure 16-1 you can see that there is a new property that specifies whether the

compiler should Embed Interop Types.

fiGure 16-1

316 .

chaPter 16 lAnguAge-SpeciFic FeATureS

When the application is compiled, any interop

types that are referenced are cloned from the PIAs

into the compiled application. In Figure 16-2 you

can see that the Microsoft.Office.Interop.

Word.Application interface as been created

within the CShaperLapAround executable.

When this application executes, the .NET

Framework 4.0 uses a new feature called type

equivalence to allow COM objects passed

between managed assemblies to be cast to a

corresponding type in the receiving assembly.

This effectively means that two assemblies can

both declare managed types that wrap a COM

object and for them to be deemed type equivalent

as if they both used the same type definition.

fiGure 16-2

Because PIA-less compilation relies on type equivalence, which is a feature of

.NET Framework 4.0, the Embed Interop Types option is available only for

projects that are compiling against the .NET Framework 4.0. With the ability for

Visual Studio 2010 to target multiple versions of the framework, it is quite easy to

accidentally create projects that are targeting an earlier version of the framework,

in which case this option would not be available.

Generic Variance

One of the seemingly confusing aspects of Generics is the role, or lack thereof, of inheritance. Take,

for example, the inheritance chain Tortoise, which inherits from Animal, which in turn inherits

from Object. You would assume that if you have a List of Tortoise (that is, List < Tortoise > in C#

or List(of Tortoise) in VB) that you could cast it back to a List of Animal. The following code

illustrates why this cannot be allowed:

c#

private void InvalidGenericCast(){

List < Tortoise > tortoiseList = new List < Tortoise > ();

List < Animal > animalList = tortoiseList;

animalList.Add(new Lion());

var notATortoise = tortoiseList[0];

}

Code snippet MainForm.cs

a Tale of Two languages .

317

Vb

Public Sub InvalidGenericCast()

Dim tortoiseList As New List(Of Tortoise)

Dim animalList As List(Of Animal) = tortoiseList

animalList.Add(New Lion)

Dim notATortoise As Tortoise = tortoiseList(0)

End Sub

Code snippet MainForm.vb

This code attempts to cast the List of Tortoise to a List of Animal. If this was allowed, a Lion

could then be added to the list, because it too inherits from Animal. This would then make the last

statement inconsistent because the List of Tortoise would no longer just contain Tortoises.

Though this illustrates a case against being able to cast between generic types, in some

circumstances casting between types is allowable. For example, the following code snippet

illustrates the List of Tortoise being cast to an IEnumerable of Animal. Because the IEnumerable

interface doesn’t permit modification of the collection, this is deemed to be a safe or allowable

conversion.

c#

private void ValidGenericCast(){

List<Tortoise> tortoiseList = new List<Tortoise>();

tortoiseList.Add(new Tortoise());

IEnumerable<Animal> animalList = tortoiseList;

var firstAnimal = animalList.First();

}

Code snippet MainForm.cs

Vb

Public Sub ValidGenericCast()

Dim tortoiseList As New List(Of Tortoise)

tortoiseList.Add(New Tortoise)

Dim animalList As IEnumerable(Of Animal) = tortoiseList

Dim firstAnimal As Animal = animalList.First()

End Sub

Code snippet MainForm.vb

The ability to convert between generic types in this way is referred to as generic variance. In

some circumstances you want to be able to narrow the type variable, such as in the preceding

example, and you want to be able to widen the type variable. These are known as covariance

and contravariance.

318 .

chaPter 16 lAnguAge-SpeciFic FeATureS

Covariance

In the previous example you saw how IEnumerable of Tortoise can be cast to an IEnumerable

of Animal. This is what is known as covariance and is allowable because the IEnumerable of T

interface has been updated to include the out keyword:

c#

public interface IEnumerable<out T> : IEnumerable{

IEnumerator<T> GetEnumerator();

}

Vb

Interface IEnumerable(Of Out T) : Inherits IEnumerable

Function GetEnumerator() As IEnumerator(Of T)

End Interface

Using the out keyword, you too can declare interfaces and delegates that have a variant type parameter.

For example, in the following code the IAnimalCreator interface allows for the type parameter to be

widened, allowing a conversion from IAnimalCreator of Lion (which MainForm implements) to

IAnimalCreator of Animal, which the DoAnimalAction method expects:

c#

public interface IAnimalCreator<out T> where T:Animal{

T CreateAnimal();

}

public partial class MainForm : Form, IAnimalCreator<Lion>{

public MainForm(){

InitializeComponent();

var animal = DoAnimalAction(this);

MessageBox.Show(animal.GetType().Name);

}

private Animal DoAnimalAction(IAnimalCreator<Animal> action) {

return action.CreateAnimal();

}

Lion IAnimalCreator<Lion>.CreateAnimal(){

return new Lion();

}

}

Code snippet MainForm.cs

Vb

Public Interface IAnimalCreator(Of Out T As Animal)

Function CreateAnimal() As Animal

End Interface

a Tale of Two languages .

319

Public Class MainForm

Implements IAnimalCreator(Of Lion)

Public Sub New()

InitializeComponent()

Dim animal = DoAnimalAction(Me)

MessageBox.Show(animal.GetType().Name)

End Sub

Public Function DoAnimalAction(ByVal action As IAnimalCreator(Of Animal)) _

As Animal

Return action.CreateAnimal()

End Function

Public Function CreateAnimal() As Animal _

Implements IAnimalCreator(Of Lion).CreateAnimal

Return New Lion

End Function

End Class

Code snippet MainForm.vb

You can see in this code that the conversion is safe because the CreateAnimal method doesn’t

accept any typed parameter (that is, a type parameter going in). Instead, the type parameter defines

the type of the return, or out, value, making the interface covariant on T.

Contravariance

Cases exist where you also want to be able to widen the type parameter. This is known as

contravariance and is used by the IComparer interface. As you can imagine, an IComparer of

Animal is also an IComparer of Lion, because if you can compare any animal you should be

able to compare Lions. This conversion is allowable because the IComparer interface has been

updated to use the in keyword.

c#

public interface IComparer<in T>{

public int Compare(T left, T right);

}

Vb

Interface IComparer(Of In T)

Function Compare(left As T, right As T) As Integer

End Interface

Again, you can use the in keyword to build your own contravariant interfaces or delegates. Using

the Animal example again, you can define a method DoAnotherAnimalAction that will accept an

IAnimalAction of Tortoise. However, the MainForm actually implements IAnimalAction of Animal.

320 .

chaPter 16 lAnguAge-SpeciFic FeATureS

c#

public interface IAnimalAction<in T> where T : Animal{

void Action(T animal);

}

public partial class MainForm : Form, IAnimalAction<Animal>{

public MainForm(){

InitializeComponent();

DoAnotherAnimalAction(this);

}

private void DoAnotherAnimalAction(IAnimalAction<Tortoise> action){

action.Action(new Tortoise());

}

void IAnimalAction<Animal>.Action(Animal animal){

MessageBox.Show("This could be any animal.... " + animal.GetType().Name);

}

}

Code snippet MainForm.cs

Vb

Public Interface IAnimalAction(Of In T As Animal)

Sub Action(ByVal animal As T)

End Interface

Public Class MainForm

Implements IAnimalCreator(Of Lion), IAnimalAction(Of Animal)

Public Sub New()

InitializeComponent()

DoAnotherAnimalAction(Me)

End Sub

Public Sub DoAnotherAnimalAction(ByVal action As IAnimalAction(Of Tortoise))

action.Action(New Tortoise)

End Sub

Public Function CreateAnimal() As Animal _

Implements IAnimalCreator(Of Lion).CreateAnimal

Return New Lion

End Function

Public Sub Action(ByVal animal As Animal) _

Implements IAnimalAction(Of Animal).Action

MessageBox.Show("This could be any animal.... " & animal.GetType().Name)

End Sub

End Class

Code snippet MainForm.vb

Visual Basic .

321

Looking at this example, you may be wondering why it is safe to perform the conversion between

an IAnimalAction of Animal to an IAnimalAction of Tortoise. This operation is safe because the

compiler enforces that the contravariant type parameter, T, can only be used as an input parameter.

Because a Tortoise can always be converted to an Animal, it is always safe to use a Tortoise as an

input parameter for a method that expects an Animal.

Visual basic

This release of Visual Basic (VB) includes a number of additions that bring it closer to feature parity

with C#. It also includes a couple of language-specific features that make it easier for developers to

initialize collections and arrays.

lambdas and anonymous Methods

One of the key omissions from previous versions of VB was full support for lambdas and anonymous

methods. An anonymous method is a method that is defined without a name and a lambda is

a special case whereby the expression can be either used to generate a delegate (as with most

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页