什么是C#相当于Haskell的新类型?

Bee*_*ers 11 c# haskell newtype

在Haskell中,有两种方法可以为类型提供别名:typenewtype.type提供类型同义词,这意味着类型检查器将同义词视为与原始类型完全相同:

type UserId = Int
hasAccess :: UserId -> Bool
hasAccess id = {-- stuff --}

-- Elsewhere in the program
login :: Int -> Bool
login n = hasAccess n -- Typechecker won't complain
Run Code Online (Sandbox Code Playgroud)

A newtype类似,但类型检查器将其视为不同类型:

newtype UserId = UserId Int
hasAccess :: UserId -> Bool
hasAccess (UserId id) = {-- stuff --}

-- Elsewhere in the program
login :: Int -> Bool
login n = hasAccess n -- Typechecker will complain, n isn't a UserId !
Run Code Online (Sandbox Code Playgroud)

在C#中,您可以使用顶级using声明定义类型同义词:

using UserId = Int;
Run Code Online (Sandbox Code Playgroud)

但是,默认情况下,C#中似乎不存在强类型的编译器检查类型别名.我已经研究了使用T4模板和CodeDOM自动生成代码以生成类包装器,但我真的不知道如何将它们干净地集成到我的编程流程中.

理想情况下,我希望能够在顶层说:

// Something like this?
using Int.UserId;

/* Elsewhere */
var id = new UserId(5);

public bool HasAccess( UserId id )
{
    /* Stuff */
}
Run Code Online (Sandbox Code Playgroud)

这使代码生成在编译时生成.如果这不可能或者为IntelliSense提供鸡蛋问题,那么每x分钟(或按钮或其他)运行的自动编译选项会很好.

Geo*_*org 17

不,C#没有这样的功能.你可以得到最接近的结构.

public struct UserId
{
    public int Id { get; private set; }

    public UserId(int id) : this() { Id = id; }
}
Run Code Online (Sandbox Code Playgroud)

这样,编译器确实将UserIdint视为不同的类型.此外,您可以添加更多方法UserId,因为您实际上int是一个用户ID.还要注意,这对运行时没有任何影响,使用带有单个int字段的结构不会导致任何int直接使用的开销.

编辑:因为您询问了T4,如果您正在使用Visual Studio,您可以轻松创建一个新的T4文本模板,该模板将扩展为(C#) - 代码并将自动编译.每次保存时都会执行模板.

  • 关于Haskell中的新类型,重要的一点是它们是一种非常便宜的抽象(实际上,它们在类型检查后已被完全优化)。从这个意义上说,结构也是正确的答案。 (2认同)