Ниже приводится пост из следующей статьи :
Различием между принуждением и кастингом часто пренебрегают. Я понимаю почему; многие языки имеют одинаковый (или аналогичный) синтаксис и терминологию для обеих операций. Некоторые языки могут даже называть любое преобразование «преобразованием», но следующее объяснение относится к концепциям CTS.
Если вы пытаетесь присвоить значение некоторого типа местоположению другого типа, вы можете сгенерировать значение нового типа, которое имеет значение, аналогичное исходному. Это принуждение. Принуждение позволяет использовать новый тип, создавая новое значение, чем-то напоминающее исходное. Некоторые приведения могут отбрасывать данные (например, преобразование int 0x12345678 в короткий 0x5678), а другие - нет (например, преобразование int 0x00000008 в короткое 0x0008 или длинное 0x0000000000000008).
Напомним, что значения могут иметь несколько типов. Если ваша ситуация немного отличается, и вы хотите выбрать только другой тип значения, приведение типов - это инструмент для работы. Приведение просто указывает, что вы хотите работать с конкретным типом, который включает значение.
Разница на уровне кода варьируется от C # до IL. В C # и приведение, и приведение выглядят довольно похоже:
static void ChangeTypes(int number, System.IO.Stream stream)
{
long longNumber = number;
short shortNumber = (short)number;
IDisposable disposableStream = stream;
System.IO.FileStream fileStream = (System.IO.FileStream)stream;
}
На уровне IL они совсем другие:
ldarg.0
conv.i8
stloc.0
ldarg.0
conv.i2
stloc.1
ldarg.1
stloc.2
ldarg.1
castclass [mscorlib]System.IO.FileStream
stloc.3
Что касается логического уровня, есть несколько важных отличий. Что наиболее важно помнить, так это то, что принуждение создает новое значение, а приведение - нет. Идентичность исходного значения и значение после преобразования одинаковы, а идентичность приведенного значения отличается от исходного значения; приведение создает новый отдельный экземпляр, а приведение - нет. Следствием этого является то, что результат преобразования и оригинал всегда будут эквивалентны (как по идентичности, так и по равенству), но приведенное значение может быть равно или не совпадать с оригиналом и никогда не разделяет исходную идентичность.
В приведенных выше примерах легко увидеть последствия принуждения, поскольку числовые типы всегда копируются по значению. Когда вы работаете со ссылочными типами, все становится немного сложнее.
class Name : Tuple<string, string>
{
public Name(string first, string last)
: base(first, last)
{
}
public static implicit operator string[](Name name)
{
return new string[] { name.Item1, name.Item2 };
}
}
В приведенном ниже примере одно преобразование - это приведение, а другое - приведение.
Tuple<string, string> tuple = name;
string[] strings = name;
После этих преобразований кортеж и имя равны, но строки не равны ни одному из них. Вы можете немного улучшить ситуацию (или немного запутать), реализовав Equals () и operator == () в классе Name для сравнения Name и строки []. Эти операторы «исправят» проблему сравнения, но у вас все равно останется два отдельных экземпляра; любая модификация строк не будет отражена в имени или кортеже, в то время как изменения одного из имени или кортежа будут отражаться в имени и кортеже, но не в строках.
Хотя приведенный выше пример предназначен для иллюстрации некоторых различий между приведением типов и приведением, он также служит отличным примером того, почему вы должны быть крайне осторожны при использовании операторов преобразования со ссылочными типами в C #.