在.NET中,什么是类型安全?

62

什么是类型安全?

它是什么意思,为什么它很重要?


可能是什么是类型安全(Type-safe)?的重复问题。 - Braiam
5个回答

81
如果您想了解“类型安全”在一般情况下的含义,那么它是指代码的特性,使开发人员确信一个值或对象将表现出特定的属性(即,属于某种类型),以便他/她可以在特定的方式下使用它而不担心意外或未定义的行为。
例如,在C#中,您可以说ArrayList类是类型安全的,因为它可以存储任何对象,这意味着您可以执行以下操作:
var integers = new ArrayList();
integers.Add(1);
integers.Add(2);
integers.Add("3");

for (int i = 0; i < integers.Count; ++i) {
    int integer = (int)integers[i];
    // do something
}

上述代码能够编译通过,因为值“3”虽然是字符串而非整数,但由于StringInt32都派生自Object,所以可以合法地将其添加到ArrayList中。然而,当您尝试将integer设置为(int)integers[2]时,它会抛出InvalidCastException异常,因为String不能被强制转换为Int32

另一方面,List<T>类恰恰因为相反的原因是类型安全的——即使上述代码不会编译,如果integersList<int>。您作为开发人员从类型安全的List<int>中访问的任何值都可以确保是一个int(或者对于任何通用List<T>,是相应的T),因此您可以确信您将能够执行操作,例如将其转换为int(显然)或long

我不同意你的观点。ArrayList 既不是类型安全的,也不是非类型安全的:https://dev59.com/zHXYa4cB1Zd3GeqP2ybt#17984521 。 - Anton Lyhin
4
他只是试图解释类型检查的重要性,他并不想解释关于数组列表特征的内容。 - clarifier

15

C - 你声明了一个int,将其强制转换为char,并访问超出int边界的内存

int i = 10;
char *s = (char*)i;
print(*(s+10));

C# - 类型安全

int i = 10;
char *s //This is invalid unless you are using unsafe context. 

.NET不直接支持指针


TypeSafe 是与 CLR 或程序的内存访问相关的东西,而不是专注于类型。因此,这个回答针对实际差异给出了 +1。参考:http://www.exforsys.com/tutorials/csharp/.-net-type-safety.html - Sumeet
C语言在没有奇怪的强制转换的情况下是类型安全的(除了非常古老的标准)。您的示例在这个领域不是很严格。您说...关于内存安全/不安全的解决方案,您能说些什么吗???带有奇怪强制转换的C#在正常部分(“非不安全”)可能会导致类型不安全:编译时为正,运行时出错。 - Jacek Cz
@JacekCz 不是的。类型安全是内存安全的一种专业化,而C甚至不是内存安全的,因为你可以像你想要的那样有缓冲区溢出、静默堆栈溢出、没有异常来防止错误行为,包括不同运算符的未定义行为。C具有弱类型系统。即使是C的指针也不是内存安全的,因为你可以进行指针算术运算。任何语言都可能导致使用后释放错误,并且不为局部变量定义初始化值,这就不是类型安全的。 - ChrisoLosoph

10
类型安全的代码只能访问它被授权访问的内存位置。例如,类型安全的代码不能从另一个对象的私有字段中读取值。它只能以明确定义、允许的方式访问类型。
在即时编译(JIT)期间,可选的验证过程会检查将要被 JIT 编译为本机机器代码的方法的元数据和 Microsoft 中间语言(MSIL),以验证它们是否是类型安全的。如果代码有权限绕过验证,则跳过此过程。
虽然类型安全的验证不是运行托管代码的强制性要求,但类型安全在程序集隔离和安全执行方面起着至关重要的作用。当代码是类型安全的时,公共语言运行库可以完全将程序集隔离开。这种隔离有助于确保程序集不能对彼此产生不良影响,并提高应用程序的可靠性。
更多参考请看 msdn 链接这里有一篇很好的文章来解释它here

2
最后一个链接已经失效。 - Banjocat

-1

你是指特定的类型安全还是一般的类型安全?

我不同意被接受的答案:ArrayList 是类型安全无知的(既不是类型安全也不是非类型安全):https://dev59.com/zHXYa4cB1Zd3GeqP2ybt#17984521

Richter - CLR via C#,第四版(第93页):

类型安全是CLR的主要特性。您可以通过调用System.Object的非虚拟GetType方法来始终发现对象的确切类型。

例如,Hero类不能重写GetType方法以成为SuperHero类型。

这个System.Object特性使CLR能够在运行时检查对象转换的可能性。例如:

internal class Employee { ... }

public sealed class Program 
{

    public static Main() 
    {
        DateTime dt = new DateTime(2016, 1, 1);
        PromoteEmployee(newYears);
    }

    public static PromoteEmployee(Object o)
    {
        Employee e = (Employee)o; //InvalidCastException, runtime error
    }
}

将 DateTime 类型转换为 Employee 类型是一种不安全的类型转换尝试的例子。

我认为,只要它不允许您执行未定义或意外的操作,就可以认为它是类型安全的。通常无法仅通过编译时分析实现类型安全(因为边界检查是需要解决停机问题的子集)。最实用的方法是进行运行时检查,并在出现问题时进行回溯失败(通过异常,仍然比崩溃或行为失常好)。有时,“向上转型”是有效的,有时则不是。您可以在类型安全的定义中禁止此类转换,但没有理由将其排除在外。 - ChrisoLosoph

-2

我不同意这里的一些答案。 C#有几个级别的安全性

编辑:类型安全有两个层面的含义(如果我们通常讨论编程语言,就像在本主题中)

一个是编译时类型安全,接近重构等,编译器捕获拼写错误,将值分配给错误变量(属性),即字符串分配给int变量。典型的C#代码是类型安全的,已知禁用此功能的方法是dynamic关键字或非泛型容器,上述错误被延迟到运行时。例如:非黑客C/C++代码在编译时(通常)是类型安全的。我认为可以在C#中编写(黑客)转换,隐藏类型冲突。

下一个级别是运行时类型安全,C#通常是安全的(没有不安全的部分)。即使动态值也会在运行时进行检查。相比之下:C/C++在运行时不安全。如果编译器接受代码,则不合逻辑的赋值在运行时不会被检查,提供奇怪/奇异/系统级或晚期错误,这是C语言的典型特征。

本主题中的一些回答者混淆了C#安全的其他领域(内存安全、范围安全、空指针等)。严格来说,这些是不同类型的安全。

理论:https://en.wikipedia.org/wiki/Type_safety

你的“编译时类型安全”被称为语义分析。困惑的人可能会称其为“静态类型安全”。他们可能认为代码没有异常,但这毫无意义,因为仅凭这种“静态类型安全”,特别是由于指针和NULL,您无法在运行时获得程序正确性或预期功能。而且,如果语言允许违规,为什么要称其为静态类型安全呢?静态类型安全将比内存安全更弱,否则静态类型安全将不是图灵完备的。静态类型安全还需要定义默认初始化。 - ChrisoLosoph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接