使用联合类型

可以在 C# 中使用联合类型,但是,由于 C# 没有真正意义上的联合类型,因此,在 C# 中使用看上去不漂亮。在这一节,我们将讨论如何在 C# 中使用联合类型,以及作为库设计人员,如何可以决定库是否公开联合类型(虽然,我个人建议避免跨语言公开联合类型)。

第一个例子,我们定义了一个简单的联合类型Quantity,它有两个构造函数,一个包含整数,另一个包含浮点数;还提供一个函数getRandomQuantity(),初始化 Quantity 的新实例。

module Strangelights.DemoModule

open System

// type that can represent a discrete or continuousquantity

type Quantity =

| Discrete of int

| Continuous of float

// initalize random number generator

let rand =
new Random()

// create a random quantity

letgetRandomQuantity() =

match rand.Next(1)
with

| 0
->Quantity.Discrete (rand.Next())

| _ ->

Quantity.Continuous

(rand.NextDouble() * float_of_int (rand.Next()))

虽然,我们提供了getRandomQuantity() 去创建 Quantity 类型的新版本,但是,类型自身也提供了静态方法,去创建组成这个类型的不同构造函数的新实例。这些静态方法在所有联合类型上都可用,它缺省由程序集公开,不需要做任何特别的事情,让编译器去创建它。下面的例子演示了如何从 C# 中使用这些方法:

using System;

using Strangelights;

static class
GetQuantityZeroClass

{

public
static void GetQuantityZero()

{

// initialize both aDiscrete and Continuous quantity

DemoModule.Quantity d =
DemoModule.Quantity.Discrete(12);

DemoModule.Quantity c =
DemoModule.Quantity.Continuous(12.0);

}

}

 

现在,我们已经知道如何从 C# 中创建联合类型,因此,下面最重要的任务就是决定构造函数属于哪一个特定的Quantity 值。可以有三种方法,下面的两段代码,我先讨论前两种方法,第三种方法要放在本节的最后。

第一种方法是可以对值的Tag 属性的分支选择(switch)。这个属性是整数,但是,因为联合类型的编译版本提供的是常量,总是有tag_ 前缀,帮助识别这个整数的含义。因此,如果想使用Tag 属性去找出是哪种类型的Quantity,通常写一个switch 语句,如下面的例子所示:

//!!! C# Source !!!

using System;

using Strangelights;

static class
GetQuantityOneClass

{

public
static void GetQuantityOne()

{

// get a randomquantity

DemoModule.Quantity q =
DemoModule.getRandomQuantity();

// use the .Tagproperty to switch over the quatity

switch (q.Tag)

{

case
DemoModule.Quantity.tag_Discrete:

Console.WriteLine("Discretevalue: {0}",q.Discrete1);

break;

case
DemoModule.Quantity.tag_Continuous:

Console.WriteLine("Continuousvalue: {0}",q.Continuous1);

break;

}

}

}

这个例子的运行的结果如下:

Discrete value: 65676

如果我们愿意,联合类型的编译形式也提供了一系列方法,前缀都是Is,用测试一个值是否属于联合类型中的特定构造函数。例如,在联合类型Quantity 中,有两个方法,IsDiscrete() 和IsContinuous(),测试Quantity 是属于Discrete,还是Continuous。下面的例子就演示了如何使用:

//!!! C# Source !!!

using System;

using Strangelights;

static class
GetQuantityTwoClass

{

public
static void GetQuantityTwo()

{

// get a randomquantity

DemoModule.Quantity q =
DemoModule.getRandomQuantity();

// use if ... elsechain to display value

if (q.IsDiscrete())

{

Console.WriteLine("Discretevalue: {0}",q.Discrete1);

}

else
if (q.IsContinuous())

{

Console.WriteLine("Continuousvalue: {0}",q.Continuous1);

}

}

}

示例的运行结果如下:

Discrete value: 2058

因为执行模式匹配所需的代码量过大,所以,这两种方法都不特别令人满意;且还有风险,如果写的代码如下所示,检测值是否是Discrete,但错误地使用了Continuous1 属性,就会出错,导致了NullReferenceException 异常。

DemoModule.EasyQuantity q =
DemoModule.getRandomEasyQuantity();

if (q.IsDiscrete())

{

Console.WriteLine("Discretevalue: {0}", q.Continuous1);

}

为给库用户提供更多的保障,为联合类型添加成员,执行模式匹配,是一个好办法。下面的例子修改了Quantity 类型,产生新类型EasyQuantity,添加两个成员,把类型转换成整数或浮点数:

module Strangelights.ImprovedModule

open System

//type that can represent a discrete or continuous quantity

//with members to improve interoperability

type
EasyQuantity =

|Discrete of
int

|Continuous of
float

// convert quantity to a float

member x.ToFloat() =

match x
with

| Discrete x -> float x

| Continuous x -> x

// convert quantity to a integer

member x.ToInt() =

match x
with

| Discrete x -> x

| Continuous x -> int x

//initalize random number generator

let rand =
new Random()

//create a random quantity

letgetRandomEasyQuantity() =

match rand.Next(1)
with

| 0 ->
EasyQuantity.Discrete (rand.Next())

| _ ->

EasyQuantity.Continuous

(rand.NextDouble() * float(rand.Next()))

这样,库用户既可把值转换成整数,也可以转换成浮点数,而不必担心模式匹配,就像下面的例子:

 

//!!! C# Source !!!

using System;

using Strangelights;

class
GetQuantityThreeClass

{

public
static void GetQuantityThree()

{

// get a randomquantity

ImprovedModule.EasyQuantity q =
ImprovedModule.getRandomEasyQuantity();

// convert quantityto a float and show it

Console.WriteLine("Value as afloat: {0}",q.ToFloat());

}

}

[

所有的示例都没有测试。

]

使用联合类型,布布扣,bubuko.com

时间: 2024-10-12 21:06:18

使用联合类型的相关文章

5.任意值、类型推论、联合类型

1.任意值any,可以将任意类型的变量赋值给该类型的变量,没有指定类型的变量默认为any 也可以用来定义不定类型的数组 2.上面说到没有指定类型的变量默认为any类型的,但是当声明变量时定义了该变量值,则默认变量为该值得类型值,这就是类型推论 若声明时未定义,则不会 3.联合类型即可以取值为多种类型中的一种 下面的例子顶你声明了一个联合类型的变量,其类型可以是string和number中的一种,不可以为其他类型,其间用"|"隔开

标C编程笔记day05 函数声明、文件读写、联合类型、枚举类型

函数声明: 1.隐式声明:在没有声明的情况下,系统可根据参数类型判断去调用函数(有可能出错) 2.显式声明:声明在被调用之前,如:double add(double,double);  函数声明参数可只写类型,不需要写函数体. 文件操作: fopen  --打开文件,FILE *pFile=fopen("a.txt","w"); fopen的打开模式: r:只能读,要求文件存在 r+:可读可写,要求文件存在 w:只能写,创建文件,如果文件存在则先删除旧文件 w+:可

TS学习随笔(二)->类型推论,联合类型

这篇内容指南:        -----类型推论  -----联合类型 类型推论 第一篇中我们看了TS的基本使用和基本数据类型的使用,知道了变量在使用的时候都得加一个类型,那我们可不可以不加呢,这个嘛,可以也不可以,为啥这木说呢,各位看官我们上眼瞧一下. 首先我们要来先了解一个概念,类型推论:如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型 例子一: let myFavoriteNumber = 'seven'; myFavo

TS——联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种. 一个小栗子 let myFavoriteNumber: string | number; myFavoriteNumber = 'seven'; myFavoriteNumber = 7; 若没有使用指定类型中的一种,将报错: let myFavoriteNumber: string | number; myFavoriteNumber = true; // index.ts(2,1): error TS2322: Type '

枚举类型与联合类型

enum类型:用途是整数和字符对应. 此处只是说明一下匿名枚举类型,enum {__ALIGN=8};此匿名枚举相当于静态常量,类似如下static const int __ALIGN=8;   union类型:共享内存的意思,有意思的是一般都是放成员数据,但还是也可以放函数,这里需要说明的是它可以被理解成一个特殊的结构体.(注意不是总是都能放函数) 在STL中有这么一个union体:union obj{union obj * free_list_link;char client_data[1]

枚举类型、联合类型

1联合union 联合 (union) 是一个能在同一个存储空间里(但不同时)存储不同类型数据的数据类型. 编译器为联合分配足够的空间保存所描述的可能性的最大需要. 下面是一个带有标记的联合模板例子: union hold{  //带有标记的联合的模板 int digit; double bigf1; char letter; }; 下面是定义3个 hold 类型联合变量的例子 union hold fit;  //hold类型的联合变量 union hold save[10]; //10个联合

从C#到TypeScript - 高级类型

C# vs TypeScript - 高级类型 上一篇讲了基础类型,基本上用基础类型足够开发了,不过如果要更高效的开发,还是要看下高级类型,这篇和C#共同点并不多,只是延用这个主题. 联合类型 可以从字面上进行理解:其实就是多个类型联合在一起,用|符号隔开.如: string | number, 表示希望这个类型既可以是string,又可以是number.联合类型的字段只能调用这些类型共同拥有的方法,除非类型推论系统自动判断出真正的类型. //这里sn就是一个联合类型的字段,由于类型推论推断出s

函数中的类型是怎么工作的

函数中的类型是怎么工作的 理解类型标记 我们已经理解函数了,看看函数中的类型是怎么工作的,还有域和范围.这只是一个概述,这个"understandingF# types"系列会为你详细介绍. 首先,我们应该多理解类型符号一点.我们之后箭头符号用于域和范围,所以它总是像函数签名: val functionName : domain -> range 看这些示例函数 : let intToString x = sprintf "x is %i" x // form

TypeScript 高级类型

一 , 交叉类型(操作符 & ): 代码 : function extend<T, U>(first: T, second: U): T & U {     let result = <T & U>{};     for (let id in first) {         (<any>result)[id] = (<any>first)[id];     }     for (let id in second) {