C# Language
Кастинг
Поиск…
замечания
Кастинг - это не то же самое, что конвертировать . Можно преобразовать строковое значение "-1"
в целочисленное значение ( -1
), но это необходимо сделать с помощью таких методов библиотеки, как Convert.ToInt32()
или Int32.Parse()
. Это невозможно сделать, используя синтаксис casting напрямую.
Передача объекта базовому типу
Учитывая следующие определения:
public interface IMyInterface1
{
string GetName();
}
public interface IMyInterface2
{
string GetName();
}
public class MyClass : IMyInterface1, IMyInterface2
{
string IMyInterface1.GetName()
{
return "IMyInterface1";
}
string IMyInterface2.GetName()
{
return "IMyInterface2";
}
}
Приведение объекта к примеру базового типа:
MyClass obj = new MyClass();
IMyInterface1 myClass1 = (IMyInterface1)obj;
IMyInterface2 myClass2 = (IMyInterface2)obj;
Console.WriteLine("I am : {0}", myClass1.GetName());
Console.WriteLine("I am : {0}", myClass2.GetName());
// Outputs :
// I am : IMyInterface1
// I am : IMyInterface2
Явное литье
Если вы знаете, что значение имеет определенный тип, вы можете явно применить его к этому типу, чтобы использовать его в контексте, где этот тип необходим.
object value = -1;
int number = (int) value;
Console.WriteLine(Math.Abs(number));
Если мы попытались передать value
непосредственно в Math.Abs()
, мы получили бы исключение для компиляции, потому что Math.Abs()
не имеет перегрузки, которая принимает object
в качестве параметра.
Если value
не может быть передано в int
, тогда вторая строка в этом примере вызовет InvalidCastException
Безопасное явное литье (оператор `as`)
Если вы не уверены, имеет ли значение тип, который, по вашему мнению, он есть, вы можете безопасно использовать его с помощью оператора as
. Если значение не относится к этому типу, результирующее значение будет равно null
.
object value = "-1";
int? number = value as int?;
if(number != null)
{
Console.WriteLine(Math.Abs(number.Value));
}
Обратите внимание, что null
значения не имеют типа, поэтому ключевое слово as
будет безопасно выдавать null
при литье любого null
значения.
Неявное литье
Значение будет автоматически передано соответствующему типу, если компилятор знает, что он всегда может быть преобразован в этот тип.
int number = -1;
object value = number;
Console.WriteLine(value);
В этом примере нам не нужно было использовать типичный синтаксис синтаксиса, поскольку компилятор знает, что все int
s могут быть переданы object
s. На самом деле мы могли бы избежать создания переменных и передать -1
непосредственно в качестве аргумента Console.WriteLine()
который ожидает object
.
Console.WriteLine(-1);
Проверка совместимости без литья
Если вам нужно знать, распространяется ли тип значения или реализует заданный тип, но вы не хотите, чтобы он действительно использовал его как этот тип, вы можете использовать оператор is
.
if(value is int)
{
Console.WriteLine(value + "is an int");
}
Явные числовые преобразования
Явные операторы литья могут использоваться для выполнения преобразований числовых типов, даже если они не расширяют или не реализуют друг друга.
double value = -1.1;
int number = (int) value;
Обратите внимание, что в случаях, когда тип назначения имеет меньшую точность, чем исходный тип, точность будет потеряна. Например, -1.1
как двойное значение в приведенном выше примере становится -1
в качестве целочисленного значения.
Кроме того, числовые преобразования основаны на типах времени компиляции, поэтому они не будут работать, если числовые типы были помещены в объекты.
object value = -1.1;
int number = (int) value; // throws InvalidCastException
Операторы преобразования
В C # типы могут определять пользовательские операторы преобразования , которые позволяют преобразовывать значения в другие типы и из других типов с использованием явных или неявных отбросов. Например, рассмотрим класс, предназначенный для представления выражения JavaScript:
public class JsExpression
{
private readonly string expression;
public JsExpression(string rawExpression)
{
this.expression = rawExpression;
}
public override string ToString()
{
return this.expression;
}
public JsExpression IsEqualTo(JsExpression other)
{
return new JsExpression("(" + this + " == " + other + ")");
}
}
Если бы мы хотели создать JsExpression, представляющее сравнение двух значений JavaScript, мы могли бы сделать что-то вроде этого:
JsExpression intExpression = new JsExpression("-1");
JsExpression doubleExpression = new JsExpression("-1.0");
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
Но мы можем добавить некоторые явные операторы преобразования в JsExpression
, чтобы обеспечить простое преобразование при использовании явного литья.
public static explicit operator JsExpression(int value)
{
return new JsExpression(value.ToString());
}
public static explicit operator JsExpression(double value)
{
return new JsExpression(value.ToString());
}
// Usage:
JsExpression intExpression = (JsExpression)(-1);
JsExpression doubleExpression = (JsExpression)(-1.0);
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
Или мы могли бы сменить эти операторы на неявные, чтобы сделать синтаксис намного проще.
public static implicit operator JsExpression(int value)
{
return new JsExpression(value.ToString());
}
public static implicit operator JsExpression(double value)
{
return new JsExpression(value.ToString());
}
// Usage:
JsExpression intExpression = -1;
Console.WriteLine(intExpression.IsEqualTo(-1.0)); // (-1 == -1.0)
LINQ Операции литья
Предположим, у вас есть такие типы, как:
interface IThing { }
class Thing : IThing { }
LINQ позволяет вам создать проекцию, которая изменяет общий тип времени компиляции IEnumerable<>
помощью методов расширения Enumerable.Cast<>()
и Enumerable.OfType<>()
.
IEnumerable<IThing> things = new IThing[] {new Thing()};
IEnumerable<Thing> things2 = things.Cast<Thing>();
IEnumerable<Thing> things3 = things.OfType<Thing>();
Когда things2
оценивается, метод Cast<>()
попытается things2
все значения в things
в Thing
s. Если он встречает значение, которое невозможно выполнить, будет InvalidCastException
.
Когда things3
оцениваются, метод OfType<>()
будет делать то же самое, за исключением того, что, если он встречает значение, которое невозможно выполнить, он просто опустит это значение, а не выбросит исключение.
Из-за общего типа этих методов они не могут вызывать Операторы преобразования или выполнять числовые преобразования.
double[] doubles = new[]{1,2,3}.Cast<double>().ToArray(); // Throws InvalidCastException
Вы можете просто выполнить бросок внутри .Select()
в качестве обходного пути:
double[] doubles = new[]{1,2,3}.Select(i => (double)i).ToArray();