当需要许多参数时,C#中的对象初始化器与构造函数

本文关键字:对象 初始化 构造函数 许多 参数 | 更新日期: 2023-09-27 18:25:06

我正在开发一个框架,以便从C#应用程序访问EVE Online API。从本质上讲,API的工作方式是客户端向EVEOnline服务器发送GET请求,然后服务器以XML文件的形式发送响应。我的框架将把这些XML文件中的信息解析为对象。无法修改请求中的信息(即无法更改客户端应用程序中的服务器数据)。因此,对象本身必须是不可变的。

现在,如果您在这里查看,您会发现有许多不同的字段,总是在每次请求时发送。例如,如果你要请求一个角色的钱包交易,你会请求

char/WalletTransactions

它会返回类似于这个的东西

<?xml version='1.0' encoding='UTF-8'?>
<eveapi version="2">
    <currentTime>2010-12-10 22:10:45</currentTime>
    <result>
        <rowset name="transactions" key="transactionID" columns="transactionDateTime,transactionID,quantity,typeName,typeID,price,clientID,clientName,stationID,stationName,transactionType,transactionFor">
            <row transactionDateTime="2010-11-24 20:33:00" transactionID="1625396969" quantity="2" typeName="Armor Plates" typeID="25605" price="314004.67" clientID="1429013925" clientName="DDV 77" stationID="60008992" stationName="Lisudeh IV - Moon 4 - Theology Council Tribunal" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-17 00:15:00" transactionID="1617616497" quantity="2393" typeName="Phased Plasma S" typeID="184" price="14.90" clientID="979676146" clientName="Kaihokohoko McIver" stationID="60001174" stationName="Lisudeh VI - Moon 2 - Kaalakiota Corporation Factory" transactionType="buy" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:58:00" transactionID="1613691673" quantity="1" typeName="Survey Scanner I" typeID="444" price="1113.09" clientID="90001413" clientName="Lucius Ventrell" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:57:00" transactionID="1613691609" quantity="2" typeName="Ship Scanner I" typeID="443" price="501.00" clientID="1612349330" clientName="Homer911" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:57:00" transactionID="1613691547" quantity="1" typeName="Rudimentary Ship Scanner I" typeID="6527" price="10.00" clientID="1551104262" clientName="Chloe TaTu" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:57:00" transactionID="1613691498" quantity="2" typeName="150mm Railgun I" typeID="565" price="5002.10" clientID="419113578" clientName="Rashim Xanadu" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:57:00" transactionID="1613691447" quantity="1" typeName="Small Hull Repairer I" typeID="524" price="14103.98" clientID="703468457" clientName="Orgazzmic" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:57:00" transactionID="1613691402" quantity="1" typeName="Dual Light Beam Laser I" typeID="452" price="3009.91" clientID="703468457" clientName="Orgazzmic" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:57:00" transactionID="1613691357" quantity="1" typeName="Small Nosferatu I" typeID="530" price="8106.77" clientID="703468457" clientName="Orgazzmic" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:56:00" transactionID="1613690953" quantity="4" typeName="Small Energy Transfer Array I" typeID="529" price="13511.27" clientID="703468457" clientName="Orgazzmic" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:56:00" transactionID="1613690800" quantity="7" typeName="Tripped Power Circuit" typeID="25598" price="90852.35" clientID="467910905" clientName="Galloway Gallegher" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
            <row transactionDateTime="2010-11-13 05:56:00" transactionID="1613690762" quantity="1" typeName="Tangled Power Conduit" typeID="25594" price="275.83" clientID="1271418001" clientName="Garthmanx" stationID="60004516" stationName="Hek IV - Krusual tribe Bureau" transactionType="sell" transactionFor="personal" />
        </rowset>
    </result>
    <cachedUntil>2010-12-10 22:25:45</cachedUntil>
</eveapi>

我需要的对象需要有每行中的所有字段(transactionDateTime、transactionID、quantity、typeName、typeID、price、clientID、clientName、stationID、stationName、transactionType、transactionFor),所以它看起来有点像

public class WalletTransaction
{
    public string TransactionDateTime { get; private set; }
    public int TransactionID { get; private set; }
    public int Quantity { get; private set; }
    public string TypeName { get; private set; }
    public int TypeID { get; private set; }
    public decimal Price { get; private set; }
    public int ClientID { get; private set; }
    public string ClientName { get; private set; }
    public int StationID { get; private set; }
    public string StationName { get; private set; }
    public Type TransactionType { get; private set; }
    public Account TransactionFor { get; private set; }
    public int JournalTransactionID { get; private set; }
    public WalletTransaction(string transactionDateTime, int transactionID,
                             int quantity, string typeName, int typeID, decimal price, int clientID,
                             string clientName, int stationID, string stationName, Type transactionType,
                             Account transactionFor, int journalTransactionID)
    {
        TransactionDateTime = transactionDateTime;
        TransactionID = transactionID;
        Quantity = quantity;
        TypeName = typeName;
        TypeID = typeID;
        Price = price;
        ClientID = clientID;
        ClientName = clientName;
        StationID = stationID;
        StationName = stationName;
        TransactionType = transactionType;
        TransactionFor = transactionFor;
        JournalTransactionID = journalTransactionID;
    }
    public enum Type
    {
        Buy,
        Sell
    }
    public enum Account
    {
        Personal,
        Computer
    }
}

正如您所看到的,这是一个相当庞大的构造函数,但对象将不会完全初始化,除非它具有从XML文件接收到的所有信息。还有许多其他对象是这样的,需要以这种方式进行操作(不可变,具有许多不同的字段)

所以问题变成了:既然对象需要是不可变的,并且需要有所有这些不同的字段,我需要使用构造函数吗;或者在这种情况下,对象初始化器会更好吗?如果他们真的想调用setter方法,就让他们调用,因为这对服务器没有任何影响?

当需要许多参数时,C#中的对象初始化器与构造函数

当从数据源(SQL、文件、XML等)创建对象时,我最喜欢做的事情之一是创建一个接受数据源本身的构造函数。

在您的情况下,您可以创建一个构造函数或静态工厂方法,该方法采用XmlNode(或者表示事务的方式)并负责从源本身读取值。

两种方法的示例:

public class WalletTransaction
{
    public string TransactionDateTime { get; private set; }
    public int TransactionID { get; private set; }
    public int Quantity { get; private set; }
    // More omitted for length
    // FACTORY METHOD (RECOMMENDED)
    public static WalletTransaction Create(XmlNode node)
    {
        return new WalletTransaction()
        {
            TransactionDateTime = node.Attributes["transactionDateTime"].Value,
            TransactionID = int.Parse(node.Attributes["transactionID"].Value),
            Quantity = int.Parse(node.Attributes["quantity"].Value)
        };
    }
    // CTOR METHOD
    public WalletTransaction(XmlNode node)
    {
        TransactionDateTime = node.Attributes["transactionDateTime"].Value;
        TransactionID = int.Parse(node.Attributes["transactionID"].Value);
        Quantity = int.Parse(node.Attributes["quantity"].Value);
    }
}

静态工厂是我在这里的首选,原因有一个。如果在构造函数中抛出异常(例如,int.Parse失败),则实际异常将封装在类型初始化异常中。静态工厂方法不会受到这个缺点的影响,并使调试变得更容易。

您也可以放弃静态方法中的字段初始值设定项列表,转而使用

var wt = new WalletTransaction();
wt.TransactionDateTime = node.Attributes["transactionDateTime"].Value;
//etc
return wt;

这样做的优点是能够进行更复杂的处理。也就是说,一个字段可能是可选的,或者只有当另一个字段设置为true时才存在。

为了使用对象初始化程序,您的属性必须具有公共setter,因此很难使它们不可变。如果你真的需要对象是不可变的,我建议你使用构造函数。