【C#點點滴滴】Deconstruct解構

2024年2月6日 22点热度 0人点赞

構造函數,是在初始化對象時,把數據傳給對象。那Deconstruct正好相反,是從對象中把想要的數據返回。

下面看一個使用場景,下面是定義一個record的Order,我們可以用元數據的方式,從Order對象中把no,orderTime取出來,這是怎麼做到的呢?

//Order定義成record
record Order(string No, DateTime OrderTime, string Address);
//使用Order
var (no, orderTime, _) = new Order("T000001", DateTime.Now, "北京市海淀區");
Console.WriteLine(no);
Console.WriteLine(orderTime);

其實實現很簡單,隻要在類內部定義一個Deconstruct的方法就可以了,下面是另一個Order為class的實例。除了基本的屬性,還實現了一個Deconstruct,參數是兩個out的參數,這個方法隻返回No和經過簡化的Goods的ID集合。這裡隻是給出一個例子,對於想把什麼數據解構出來,以什麼形式解構出來,可以根據自己的需要。同時Deconstruct可以有重載,但是,參數一樣時,函數就有二義性了。【其確我覺得可以通過(string no,List<int> goodsIds)來解決二義性,但現在不好用】

class Order
{
    public Order(string no, DateTime orderTime, string address)
    {
        No = no;
        OrderTime = orderTime;
        Address = address;
    }
    public string No { get; set; }
    public DateTime OrderTime { get; set; }
    public string Address { get; set; }
    public List<Goods> Goodses { get; set; } = new List<Goods>();
    public void Deconstruct(out string no, out List<int> goodsIds)
    {
        no = No;
        goodsIds = Goodses.Select(a => a.ID).ToList();
    }
    public void Deconstruct(out string no, out DateTime orderTime)
    {
        no = No;
        orderTime = OrderTime;
    }   
}
var (no, goodsIds) = new Order("T000001", DateTime.Now, "北京市海淀區")
{
    Goodses = new List<Goods>
    {
        new Goods { ID = 1, Name = "商品A", Price = 10m },
        new Goods { ID = 2, Name = "商品B", Price = 15m },
    }
};
Console.WriteLine($"OrderNo:{no}");
foreach (var goodsId in goodsIds)
{
    Console.WriteLine($"    GoodsId:{goodsId}");
}

另外,Deconstruct可以通過擴展的方式,給一些類型增加解構功能,下面是對Exception的解構,取出Message和InnerException,當然這隻是一個Demo,隻提供了一條路子,具體應用可以靈活定義。

static class ExceptionExtensions
{
    public static void Deconstruct(this Exception? exception, out string? message, out Exception? innerException)
    {
        message = exception?.Message;
        innerException = exception?.InnerException;
    }
    public static void Deconstruct(this Exception? exception, out string? message, out string? innerMessage, out Exception? innerInnerException)
    {
        message = exception?.Message;
        innerMessage = exception?.InnerException?.Message;
        innerInnerException = exception?.InnerException?.InnerException;
    }    
}
try
{
    throw new Exception("1級錯誤", new Exception("2級錯誤"));
}
catch (Exception exc)
{
    var (msg, (innerMsg, _)) = exc;
    Console.WriteLine(msg);
    Console.WriteLine(innerMsg);
}

奇奇怪怪的C#知識又增加了一點。