关于c#:C中的类型转换自定义隐式转换和显式转换

1次阅读

共计 3975 个字符,预计需要花费 10 分钟才能阅读完成。

起源:https://note.guoqianfan.com/2…

前言

有时咱们会遇到这么一种状况:在 json 数据里,数组里的数据类型 不统一,导致咱们不能间接反序列化为指标类型。最终咱们只能反序列化为 JObject 类型,而后通过字符串取值的形式来取出数据。

上面介绍一种新形式:通过 自定义隐式转换,把不一样的数据类型反序列化为一样的数据类型。

基础知识

类型转换有 2 种:隐式转换和显式转换。然而,不论是隐式转换,还是显式转换,都是生成了一个新对象返回的。扭转新对象的属性,不会影响老对象!(dynamic 对象 除外,详情搜寻dynamic 动静类型)

自定义隐式 / 显式转换的办法须要用到几个关键字:implicit(隐式转换)、explicit(显式转换)、operator(操作符)。更多的留神点见下:

  1. 办法必須是 static
  2. 应用 implicitexplicit
  3. 搭配operator(此也是 c# 關鍵字,可在類別或結構宣告內多載內建運算子或提供使用者定義的轉換)
  4. 返回值 为要转换为的指标类型,但不要在办法上申明,办法名 指标类型 。留神: 返回值不肯定是本类类型 。本类型和其余类型之间能够 相互转换,只有定义转换方法就行。
  5. 参数 为原始类型,办法名 指标类型
  6. 类 A 到类 B 的类型转换定义不能在类 C 中进行(即 2 个类的转换不能在第 3 个类中定义),否则会报错:用户定义的转换必须是转换成关闭类型,或者从关闭类型转换。具体查看前面的用户定义的转换必须是转换成关闭类型,或者从关闭类型转换
  7. 不能被 virtual/override 润饰(不能“笼罩”运算符,因为它们是动态的。)Overriding implicit operators in C#

示例代码

//================ 定义类型和办法 ================
class Robot
{public int Id { get; set;}
    public string Name {get; set;}

    public Robot(int id, string name)
    {
        Id = id;
        Name = name;
    }

    #region 其余类型 -> 本类

    // 隐式转换
    public static implicit operator Robot(string name)
    {return new Robot(101, name);
    }

    // 显式转换
    public static explicit operator Robot(int id)
    {return new Robot(id, "miku");
    }

    #endregion

    #region 本类 -> 其余类型

    // 隐式转换
    public static implicit operator string(Robot robot)
    {return robot.Name;}

    // 显式转换
    public static explicit operator int(Robot robot)
    {return robot.Id;}

    #endregion
}

//================ 测试代码 ================
#region 其余类型 -> 本类

string gumiStr = "gumi";
Robot gumi001 = gumiStr; // 隐式转换
Console.WriteLine("隐式转换:gumi001 : {0}", JsonConvert.SerializeObject(gumi001));

int lukaId = 1004;
Robot luka001 = (Robot)lukaId; // 显式转换
Console.WriteLine("显式转换:luka001 : {0}", JsonConvert.SerializeObject(luka001));

#endregion

#region 其余类型 -> 本类

Robot miku001 = new Robot(1001, "miku10001");
// 隐式转换
string mikuName = miku001;
// 显式转换
int mikuId = (int)miku001;

Console.WriteLine("隐式转换:miku001 Name: {0}", mikuName);
Console.WriteLine("显式转换:miku001 Id: {0}", mikuId);

#endregion

输入后果如下:

隐式转换:gumi001 : {"Id":101,"Name":"gumi"}
显式转换:luka001 : {"Id":1004,"Name":"miku"}
隐式转换:miku001 Name: miku10001
显式转换:miku001 Id: 1001

理论利用

问题

[1,[[2,2],[2,2],[2,2],[2,2]]]

这样一个字符串,如何能够反序列化成一个对象?(如何定义这个类?)

答案

using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
                    
public class Program
{public static void Main()
    {var json = "[1,[[2,2],[2,2],[2,2],[2,2]]]";
        var root = JsonConvert.DeserializeObject<Root>(json);
        foreach(var ele in root)
        {if(ele.SingleValue.HasValue)
            {// 有值,原始数据为 1
                Console.WriteLine(ele.SingleValue.Value);
            }else
            {// 原始数据为 二维数组
                Console.WriteLine(string.Join("",ele.Select(x=>string.Join(",",x))));
            }
        }
        Console.WriteLine(JsonConvert.SerializeObject(root));
    }
}

class Root : List<Element> { }
[JsonConverter(typeof(CConverter))]
class Element : List<List<long>>
{
    // 该属性,寄存 1。后续能够通过判断该属性是否有值来得悉原始数据的状况
    public long? SingleValue {get; set;}

    // 遇到 1,隐式转换为 该类型,其中 1 被寄存到 SingleValue 属性
    public static implicit operator Element(long d)
    {return new Element { SingleValue = d};
    }
}

public class CConverter : JsonConverter
{public override bool CanConvert(Type objectType)
    {return (objectType == typeof(Element));
    }

    public override bool CanRead  {get { return false;} }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var ele = value as Element;
        var token = ele.SingleValue.HasValue ? JToken.FromObject(ele.SingleValue.Value) : JToken.FromObject(ele.ToList());
        token.WriteTo(writer);
    }

    public override bool CanWrite {get { return true;} }
}

报错

用户定义的转换必须是转换成关闭类型,或者从关闭类型转换

这个谬误,与关闭类型无关

是因为有这个限度:类 A 到类 B 的类型转换定义不能在类 C 中进行(即 2 个类的转换不能在第 3 个类中定义)

所以对于指标类型是汇合类List<T>,咱们无奈间接定义到它的转换。不过,有 2 个曲折的办法:

  • 创立个类 继承 自汇合类List<T>,定义到这个子类的转换。下面理论利用中的代码就是这样做的:class Element : List<List<long>>
  • 创立 T1T2的自定义转换,应用时一一转换:list.Select(p=>(B)p).ToList()

参考

  1. 隐式转换:用户定义的转换必须是转换成关闭类型,或者从关闭类型转换:https://blog.csdn.net/kamui_s…

其余

利用和设计

在定義類別時,如果有须要,就能够应用這兩個關鍵字來提供類別一些額外的性能

但在应用時也必須考慮設計上是否正当

例如當兩類別有相關性時是否該提取出父类或是接口來应用,而不是為了不便做了一堆轉換,導致程式撰寫與維護上的困難。

读音

  • 隐式转换:implicit [ɪmˈplɪsɪt] adj. 不言明 [宛转] 的; 无疑问的,相对的; 成为一部份的; 内含的;
  • 显式转换:explicit [ɪkˈsplɪsɪt] adj. 明确的,分明的; 婉言的; 详述的; 不瞒哄的;

参考

  1. 【问】这样一个字符串如何反序列化:http://www.newsmth.net/nForum…
  2. 型別轉換關鍵字 explicit 與 implicit 的用法:https://dotblogs.com.tw/lasts…
  3. c# 关键词 implicit 和 explicit:https://blog.csdn.net/Joyhen/…
正文完
 0