.net类型自定义隐式(显式)转换操作的位置问题

本文探讨了C#中自定义类的隐式与显式转换操作符的应用及注意事项,通过实验验证了不同转换场景下的行为表现。

   最近在学习.net基础的东西,今晚上学习转换操作符方法,对类自定义隐式(显式)转换操作符进行了一些研究,发现了自定义隐式(显式)操作符需要注意的一个小问题。

   我假设现在有个Rat类,如果要进行Rat r1 = 5; Int32 x = (Int32) r1; 我们需要给Rat类定义一个由一个Int32隐式构造一个Rat并返回的操作符,和一个由一个Rat显式构造一个Int32并返回操作符

  具体代码如下:

ContractedBlock.gif ExpandedBlockStart.gif Code
 1using System;
 2
 3class Rat
 4ExpandedBlockStart.gifContractedBlock.gif{
 5  //一个普通字段
 6  public Int32 numR;
 7  
 8  //实例构造器
 9  public Rat(Int32 numr)
10ExpandedSubBlockStart.gifContractedSubBlock.gif  {
11    numR = numr;
12  }

13  
14  //转换成Int32类型
15  public Int32 ToInt32()
16ExpandedSubBlockStart.gifContractedSubBlock.gif  {
17    return numR;
18  }
 
19
20  //由一个Int32隐式构造一个Rat并返回
21  public static implicit operator Rat(Int32 numerator)
22ExpandedSubBlockStart.gifContractedSubBlock.gif  {
23   return new Rat(numerator);
24  }

25  
26  //由一个Rat显式构造一个Int32并返回
27  public static explicit operator Int32(Rat r)
28ExpandedSubBlockStart.gifContractedSubBlock.gif  {
29   return r.ToInt32();
30  }

31}

32
33class App 
34ExpandedBlockStart.gifContractedBlock.gif{
35  static void Main()
36ExpandedSubBlockStart.gifContractedSubBlock.gif  {
37   Rat r1 = 5;
38   Int32 x = (Int32) r1;
39   System.Console.WriteLine(r1.numR.ToString());
40   System.Console.WriteLine(x.ToString());
41  }

42}

上面代码输出:

你可以发现我把其他类型转换成本类型时定义为隐式转换(Int32转换成Rat),把本类转换成其他类型时定义为显式转换(Rat转换成Int32)。

那么可以为Rat定义一个由一个Rat隐式构造一个Int32并返回方法吗?经过试验发现是可行的(,那么问题来了,假如Int32中同样定义了一个Rat隐式构造一个Int32并返回方法(ps:这里的意思是假如,毕竟Int32是元类型),此时进行一个Rat到Int32的隐式转换会出错吗?

(因为Int32是元类型,我们现在自定义一个Bat类替代Int32来继续试验)

出于好奇我写出下面的代码:

ContractedBlock.gif ExpandedBlockStart.gif Code
 1using System;
 2class Bat
 3ExpandedBlockStart.gifContractedBlock.gif{
 4  public Int32 numR;
 5  public Bat(Int32 numr)
 6ExpandedSubBlockStart.gifContractedSubBlock.gif  {
 7    numR = numr;
 8  }

 9
10  public static implicit operator Bat(Rat r)
11ExpandedSubBlockStart.gifContractedSubBlock.gif  {
12   return new Bat(22222222);
13  }
    
14}

15
16class Rat
17ExpandedBlockStart.gifContractedBlock.gif{
18  public Int32 numR;
19  public Rat(Int32 numr)
20ExpandedSubBlockStart.gifContractedSubBlock.gif  {
21    numR = numr;
22  }

23 
24  public static implicit operator Bat(Rat r)
25ExpandedSubBlockStart.gifContractedSubBlock.gif  {
26   return new Bat(1111111);
27  }
    
28}

29
30class App 
31ExpandedBlockStart.gifContractedBlock.gif{
32  static void Main()
33ExpandedSubBlockStart.gifContractedSubBlock.gif  {
34   Rat r1 = new Rat(5);
35   Bat b1 = r1;
36   System.Console.WriteLine(r1.numR.ToString());
37   System.Console.WriteLine(b1.numR.ToString());
38  }

39}

结果编译失败:

继续猜测如果不进行隐式转换,是不是两个类可以同时定义相同隐式转换呢?

注释Mian()内部分代码后:

ContractedBlock.gif ExpandedBlockStart.gif Code
 1using System;
 2class Bat
 3ExpandedBlockStart.gifContractedBlock.gif{
 4  public Int32 numR;
 5  public Bat(Int32 numr)
 6ExpandedSubBlockStart.gifContractedSubBlock.gif  {
 7    numR = numr;
 8  }
 9
10  public static implicit operator Bat(Rat r)
11ExpandedSubBlockStart.gifContractedSubBlock.gif  {
12   return new Bat(22222222);
13  }    
14}
15
16class Rat
17ExpandedBlockStart.gifContractedBlock.gif{
18  public Int32 numR;
19  public Rat(Int32 numr)
20ExpandedSubBlockStart.gifContractedSubBlock.gif  {
21    numR = numr;
22  }
23 
24  public static implicit operator Bat(Rat r)
25ExpandedSubBlockStart.gifContractedSubBlock.gif  {
26   return new Bat(1111111);
27  }    
28}
29
30class App 
31ExpandedBlockStart.gifContractedBlock.gif{
32  static void Main()
33ExpandedSubBlockStart.gifContractedSubBlock.gif  {
34   Rat r1 = new Rat(5);
35   //Bat b1 = r1;
36   //System.Console.WriteLine(r1.numR.ToString());
37  // System.Console.WriteLine(b1.numR.ToString());
38  }

39}

结果编译成功,用ildasm工具打开编译后的198a.exe查看结果是

 

可以看到类Bat和Rat都有一个叫olmplicit:class Bat(class Rat)的隐式转换操作定义。那么内部定义是否一样呢?

点击查看如下:

可以看出是完全一样的两个隐式转换定义。

ok把试验进行到底,现在把Rat类中隐式定义去掉:

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;
class Bat
{
  
public Int32 numR;
  
public Bat(Int32 numr)
  {
    numR 
= numr;
  }

  
public static implicit operator Bat(Rat r)
  {
   
return new Bat(22222222);
  }    
}

class Rat
{
  
public Int32 numR;
  
public Rat(Int32 numr)
  {
    numR 
= numr;
  }
 
  
//public static implicit operator Bat(Rat r)
  
//{
  
// return new Bat(1111111);
  
//}    
}

class App 
{
  
static void Main()
  {
   Rat r1 
= new Rat(5);
   Bat b1 
= r1;
   System.Console.WriteLine(r1.numR.ToString());
   System.Console.WriteLine(b1.numR.ToString());
  }
}

编译成功,并运行得到如下图结果:

可以看到Clr成功的调用了Bat类中定义的隐式Rat转换Bat的操作

我们用ildasm查看编译结果:

再把Bat的隐式转换去掉,让Rat类中存在一个隐式转换。

编译成功,运行结果是:

好了现在来总结下:C#没有对隐式(显式)转换操作的定义位置强制要求,但是你会发现不当的定义将会发生错误,假设下如果几个小组同时进行开发每个小组都有自己的程序集,如果对隐式(显式)转换操作的定义没有个统一的规范会带来错误,我们是不是应该建议这么定义隐式(显式)转换操作:把其他类型转换成本类型时全部定义为隐式式转换,把本类转换成其他类型时定义全部进行显示转换。(ps:也许这个问题早就有规范了只是我不知道呵呵,深夜沪被小雨洗刷的这么安静,我顶着感冒,享受着思考带来的快乐

 

转载于:https://www.cnblogs.com/yatasoft/archive/2008/11/23/1339208.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值