C# 转换操作符方法
🏷️ 《CLR via C#》
转换操作符方法
CLR 规范要求转换操作符重载方法必须是 public
和 static
方法。
此外,C# 要求参数类型和返回类型二者必有其一与定义转换方法的类型相同。
cs
/// <summary>
/// 由一个 Int32 隐式构造并返回一个 Rational
/// </summary>
/// <param name="num"></param>
public static implicit operator Rational(Int32 num)
{
return new Rational(num);
}
/// <summary>
/// 由一个 Rational 显示返回一个 Int32
/// </summary>
/// <param name="r"></param>
public static explicit operator Int32(Rational r)
{
return r.ToInt32();
}
完整示例代码
cs
public sealed class Rational
{
Single _value;
/// <summary>
/// 由一个 Int32 构造一个 Rational
/// </summary>
/// <param name="num"></param>
public Rational (Int32 num)
{
_value = (Single)num;
}
/// <summary>
/// 由一个 Single 构造一个 Rational
/// </summary>
/// <param name="num"></param>
public Rational (Single num)
{
_value = num;
}
/// <summary>
/// 将一个 Rational 转换成 Int32
/// </summary>
/// <returns></returns>
public Int32 ToInt32()
{
return (Int32)_value;
}
/// <summary>
/// 将一个 Rational 转换成 Single
/// </summary>
/// <returns></returns>
public Single ToSingle()
{
return _value;
}
/// <summary>
/// 由一个 Int32 隐式构造并返回一个 Rational
/// </summary>
/// <param name="num"></param>
public static implicit operator Rational(Int32 num)
{
return new Rational(num);
}
/// <summary>
/// 由一个 Single 隐式构造并返回一个 Rational
/// </summary>
/// <param name="num"></param>
public static implicit operator Rational(Single num)
{
return new Rational(num);
}
/// <summary>
/// 由一个 Rational 显示返回一个 Int32
/// </summary>
/// <param name="r"></param>
public static explicit operator Int32(Rational r)
{
return r.ToInt32();
}
/// <summary>
/// 由一个 Rational 显示返回一个 Single
/// </summary>
/// <param name="r"></param>
public static explicit operator Single(Rational r)
{
return r.ToSingle();
}
}
调用示例
cs
Rational r1 = 5; // Int32 隐式转型为 Rational
Rational r2 = 2.5F; // Single 隐式转型为 Rational
Int32 x = (Int32)r1; // Rational 显式转型为 Int32
Single y = (Single)r1; // Rational 显式转型为 Single
IL 代码
Rational 类 IL 代码
将对象从一种类型转换成另一种类型的方法总是叫做 op_Implicit
或者 op_Explicit
方法。
只有在转换不损失精度或者数量级的前提下,才能定义隐式转换操作符。
如果转换会造成精度或数量级损失,就应该定义一个显示转换操作符。
显示转换失败,应该让显示转换操作符方法抛出 OverflowException
或者 InvalidOperationException
异常。
查看 IL 代码
cs
.class public sealed auto ansi beforefieldinit
ConsoleApp1.Rational
extends [mscorlib]System.Object
{
.field private float32 _value
.method public hidebysig specialname rtspecialname instance void
.ctor(
int32 num
) cil managed
{
.maxstack 8
// [17 9 - 17 36]
IL_0000: ldarg.0 // this
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
// [18 9 - 18 10]
IL_0007: nop
// [19 13 - 19 34]
IL_0008: ldarg.0 // this
IL_0009: ldarg.1 // num
IL_000a: conv.r4
IL_000b: stfld float32 ConsoleApp1.Rational::_value
// [20 9 - 20 10]
IL_0010: ret
} // end of method Rational::.ctor
.method public hidebysig specialname rtspecialname instance void
.ctor(
float32 num
) cil managed
{
.maxstack 8
// [26 9 - 26 37]
IL_0000: ldarg.0 // this
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
// [27 9 - 27 10]
IL_0007: nop
// [28 13 - 28 26]
IL_0008: ldarg.0 // this
IL_0009: ldarg.1 // num
IL_000a: stfld float32 ConsoleApp1.Rational::_value
// [29 9 - 29 10]
IL_000f: ret
} // end of method Rational::.ctor
.method public hidebysig instance int32
ToInt32() cil managed
{
.maxstack 1
.locals init (
[0] int32 V_0
)
// [36 9 - 36 10]
IL_0000: nop
// [37 13 - 37 34]
IL_0001: ldarg.0 // this
IL_0002: ldfld float32 ConsoleApp1.Rational::_value
IL_0007: conv.i4
IL_0008: stloc.0 // V_0
IL_0009: br.s IL_000b
// [38 9 - 38 10]
IL_000b: ldloc.0 // V_0
IL_000c: ret
} // end of method Rational::ToInt32
.method public hidebysig instance float32
ToSingle() cil managed
{
.maxstack 1
.locals init (
[0] float32 V_0
)
// [45 9 - 45 10]
IL_0000: nop
// [46 13 - 46 27]
IL_0001: ldarg.0 // this
IL_0002: ldfld float32 ConsoleApp1.Rational::_value
IL_0007: stloc.0 // V_0
IL_0008: br.s IL_000a
// [47 9 - 47 10]
IL_000a: ldloc.0 // V_0
IL_000b: ret
} // end of method Rational::ToSingle
.method public hidebysig static specialname class ConsoleApp1.Rational
op_Implicit(
int32 num
) cil managed
{
.maxstack 1
.locals init (
[0] class ConsoleApp1.Rational V_0
)
// [54 9 - 54 10]
IL_0000: nop
// [55 13 - 55 38]
IL_0001: ldarg.0 // num
IL_0002: newobj instance void ConsoleApp1.Rational::.ctor(int32)
IL_0007: stloc.0 // V_0
IL_0008: br.s IL_000a
// [56 9 - 56 10]
IL_000a: ldloc.0 // V_0
IL_000b: ret
} // end of method Rational::op_Implicit
.method public hidebysig static specialname class ConsoleApp1.Rational
op_Implicit(
float32 num
) cil managed
{
.maxstack 1
.locals init (
[0] class ConsoleApp1.Rational V_0
)
// [63 9 - 63 10]
IL_0000: nop
// [64 13 - 64 38]
IL_0001: ldarg.0 // num
IL_0002: newobj instance void ConsoleApp1.Rational::.ctor(float32)
IL_0007: stloc.0 // V_0
IL_0008: br.s IL_000a
// [65 9 - 65 10]
IL_000a: ldloc.0 // V_0
IL_000b: ret
} // end of method Rational::op_Implicit
.method public hidebysig static specialname int32
op_Explicit(
class ConsoleApp1.Rational r
) cil managed
{
.maxstack 1
.locals init (
[0] int32 V_0
)
// [72 9 - 72 10]
IL_0000: nop
// [73 13 - 73 32]
IL_0001: ldarg.0 // r
IL_0002: callvirt instance int32 ConsoleApp1.Rational::ToInt32()
IL_0007: stloc.0 // V_0
IL_0008: br.s IL_000a
// [74 9 - 74 10]
IL_000a: ldloc.0 // V_0
IL_000b: ret
} // end of method Rational::op_Explicit
.method public hidebysig static specialname float32
op_Explicit(
class ConsoleApp1.Rational r
) cil managed
{
.maxstack 1
.locals init (
[0] float32 V_0
)
// [81 9 - 81 10]
IL_0000: nop
// [82 13 - 82 33]
IL_0001: ldarg.0 // r
IL_0002: callvirt instance float32 ConsoleApp1.Rational::ToSingle()
IL_0007: stloc.0 // V_0
IL_0008: br.s IL_000a
// [83 9 - 83 10]
IL_000a: ldloc.0 // V_0
IL_000b: ret
} // end of method Rational::op_Explicit
} // end of class ConsoleApp1.Rational
调用示例 IL 代码
隐式转换调用的 op_Implicit
方法;显示转换调用的 op_Explicit
方法。
cs
// [13 13 - 13 29]
IL_0001: ldc.i4.5
IL_0002: call class ConsoleApp1.Rational ConsoleApp1.Rational::op_Implicit(int32)
IL_0007: stloc.0 // r1
// [14 13 - 14 32]
IL_0008: ldc.r4 2.5
IL_000d: call class ConsoleApp1.Rational ConsoleApp1.Rational::op_Implicit(float32)
IL_0012: stloc.1 // r2
// [16 13 - 16 33]
IL_0013: ldloc.0 // r1
IL_0014: call int32 ConsoleApp1.Rational::op_Explicit(class ConsoleApp1.Rational)
IL_0019: stloc.2 // x
// [17 13 - 17 35]
IL_001a: ldloc.0 // r1
IL_001b: call float32 ConsoleApp1.Rational::op_Explicit(class ConsoleApp1.Rational)
IL_0020: conv.r4
IL_0021: stloc.3 // y