ToString()和 implicit operator string的区别

本文详细解析了C#中Console.WriteLine()方法如何处理自定义类型,通过一个Currency结构体示例展示了隐式类型转换与ToString()方法的调用顺序。当存在隐式转换时,WriteLine()会首先尝试隐式转换,否则调用ToString()。而在字符串插值中,$会直接调用ToString()方法,不涉及隐式转换。理解这些规则对于编写高效且清晰的代码至关重要。

写这篇文章是来源于一次关于Cast和ConsoleWriteline()的研究。

ConsoleWriteline()是一个在终端输出的简单方法,但是它输出原理是什么?下面给出一个例子。

    public struct Currency
    {
        public uint Dollars { get; }
        public ushort Cents { get; }

        public Currency(uint dollars, ushort cents)
        {
            Dollars = dollars;
            Cents = cents;
        }
        
        public override string ToString() => $"${Dollars}.{Cents,-2:00}";
        public static implicit operator string (Currency value) => "Currency";
   }

先看ToString()和 public static implicit operator string (Currency value) => “Currency”; 第 一个是重写方法,第二个是隐式转换。
那么调用以下代码输出

                Currency balance = new Currency(50, 35); 
                Console.WriteLine(balance);
                Console.WriteLine($"balance is {balance}");

输出结果
在这里插入图片描述
可以看出第一个writeline调用了隐式转换,第二个writeline 调用了ToString()方法。
所以其中隐含的代码应该是这样的

                Console.WriteLine((string)balance);
                Console.WriteLine($"balance is {balance.ToString()}");

但是如果注释掉隐式转换//public static implicit operator string (Currency value) => “Currency”;
输出结果就变成了:
在这里插入图片描述
如果注释掉ToString()//public override string ToString() => """{Dollars}.{Cents,-2:00}";
输出结果就变成了:
在这里插入图片描述

所以这里揭示了两个规则,第一,隐式转换优先级高于ToString()方法,WriteLine(balance)先检查隐式转换符是否存在,如果不存在则调用ToString()方法。第二,$相当于String.Format()简化,String.Format()里面的参数并不会调用隐式转换,而是直接调用ToString()方法,由于重写方法被注释,所以调用了默认的ValueType.ToString()方法,。

using System.Text.Json.Serialization; using System.Text.Json; namespace Domain.Models.Common { [JsonConverter(typeof(DateJsonConverter))] public readonly record struct Date(DateTime Value) { public Date(string date) : this(DateTime.Parse(date)) { } public static implicit operator Date(DateTime dt) => new(dt); public static implicit operator DateTime(Date d) => d.Value; public override string ToString() => Value.ToString("yyyy-MM-dd"); public Date AddDays(int days) => new(Value.AddDays(days)); } public class DateJsonConverter : JsonConverter<Date?> { public override Date? Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) { var str = reader.GetString(); return string.IsNullOrWhiteSpace(str) ? null : new Date(str); } public override void Write(Utf8JsonWriter writer, Date? value, JsonSerializerOptions options) => writer.WriteStringValue(value?.ToString() ?? null); } } using Dapper; using Domain.Models.Common; namespace Infrastructure.Database { public class DataTypeHandle { public class DateTypeHandler : SqlMapper.TypeHandler<Date?> { public override Date? Parse(object value) => value is DBNull ? null : new Date((DateTime)value); public override void SetValue(IDbDataParameter parameter, Date? value) { parameter.DbType = DbType.Date; parameter.Value = value?.Value ?? (object)DBNull.Value; } } } } 系統發生報錯 An unhandled exception occurred while processing the request. InvalidOperationException: The converter specified on 'Domain.Models.Common.Date' is not compatible with the type 'Domain.Models.Common.Date'. System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializationConverterOnAttributeNotCompatible(Type classTypeAttributeIsOn, MemberInfo memberInfo, Type typeToConvert) 但如果這樣修改,系統就不會報錯 public class DateJsonConverter : JsonConverter<Date> { public override Date Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) { var str = reader.GetString(); return new Date(str); } public override void Write(Utf8JsonWriter writer, Date value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString() ?? null); } .net 8.0 mvc框架 請分析原因,我希望一個可以處理null值的date類型
最新发布
05-22
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值