構造函數,是在初始化對象時,把數據傳給對象。那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#知識又增加了一點。