【问题标题】:Copy array of objects to array of different type将对象数组复制到不同类型的数组
【发布时间】:2009-03-24 20:03:43
【问题描述】:

以前,我在尝试在我的 ASMX 网络服务和我的 .aspx 页面(网络客户端)之间共享类型定义时遇到了问题

Confused on C# Array of objects and implicit type conversion

据我了解,这产生的“问题”可以通过将客户端中创建的对象数组复制到由 ASMX 代理类定义的新对象数组来解决。

作为 C# 的新手,我仍在为这个简单的任务而苦苦挣扎。以下是我的代码的更多部分(上一篇文章中的其他片段保持不变):

...这里是我填充要传递给 Web 服务的“测试数据”的地方:

// create an array of MetaData objects
MetaData[] nvPairs = new MetaData[20];   // arbitrary length of 20 pairs

// create arbitrary MetaData objects in the array
nvPairs[0] = new MetaData("Grant Number", "2577-9912");
nvPairs[1] = new MetaData("OPEAnalyst", "Simpson");

...在这里,我尝试使用一个函数将我的 TRIMBrokerUtil 命名空间中定义的“真实”类型(由于代理而无法完全使用)“复制”到该类型的代理版本:

protected TRIMBrokerASMXProxy.ASMXProxy.MetaData[] CopyMetaData(
    MetaData utilArray)
{
    TRIMBrokerASMXProxy.ASMXProxy.MetaData[] outArray = 
        new TRIMBrokerASMXProxy.ASMXProxy.MetaData[utilArray.Name.Length];
    int i;
    for (i = 0; i < utilArray.Name.Length; i++)
    {
        outArray[i].Name = utilArray.Name;
        outArray[i].Value = utilArray.Value;
    }
    return outArray;
}

...然后在这里我尝试调用该函数(编译器在此行标记 2 个错误:

TRIMBrokerASMXProxy.ASMXProxy.MetaData[] kvData = 
    CopyMetaData(metaDataArray); 

下面的两个编译错误都指向同一行:

错误 1 ​​'_Default.CopyMetaData(TRIMBrokerUtil.MetaData)' 的最佳重载方法匹配有一些无效参数

错误 2 参数“1”:无法从“TRIMBrokerUtil.MetaData[]”转换为“TRIMBrokerUtil.MetaData”

我接近了吗?

【问题讨论】:

    标签: c# arrays object copying


    【解决方案1】:

    您已将参数声明为 MetaData 而不是 MetaData[] - 换句话说,它不是一个数组。然后你会经常使用utilArray.Name,但不清楚原因。

    我怀疑你真的想要:

    protected TRIMBrokerASMXProxy.ASMXProxy.MetaData[]
        CopyMetaData(MetaData[] utilArray)
    {
        TRIMBrokerASMXProxy.ASMXProxy.MetaData[] outArray = 
            new TRIMBrokerASMXProxy.ASMXProxy.MetaData[utilArray.Length];
        for (int i = 0; i < utilArray.Length; i++)
        {
            outArray[i] = new TRIMBrokerASMXProxy.ASMXProxy.MetaData();
            outArray[i].Name = utilArray[i].Name;
            outArray[i].Value = utilArray[i].Value;
        }
        return outArray;
    }
    

    顺便说一句,您可能需要考虑使用using 指令以使其更易于阅读:

    using ProxyMetaData = TRIMBrokerASMXProxy.ASMXProxy.MetaData;
    
    ...
    
    protected ProxyMetaData[] CopyMetaData(MetaData[] utilArray)
    {
        ProxyMetaData[] outArray = new ProxyMetaData[utilArray.Length];
        for (int i = 0; i < utilArray.Length; i++)
        {
            outArray[i] = new ProxyMetaData();
            outArray[i].Name = utilArray[i].Name;
            outArray[i].Value = utilArray[i].Value;
        }
        return outArray;
    }
    

    另一种选择是Array.ConvertAll:

    ProxyMetaData[] output = Array.ConvertAll(input,
        metaData => new ProxyMetaData(metaData.Name, metaData.Value));
    

    如果您不使用 C# 3,则可以使用匿名方法。如果ProxyMetaData 没有合适的构造函数,而您正在使用 C# 3,则可以使用对象初始化器:

    ProxyMetaData[] output = Array.ConvertAll(input,
        metaData => new ProxyMetaData { metaData.Name, metaData.Value });
    

    如果你被 C# 2 困住并且没有合适的构造函数,那么:

    ProxyMetaData[] output = Array.ConvertAll(input, delegate(MetaData metaData)
    {
        ProxyMetaData proxy = new ProxyMetaData();
        proxy.Name = metaData.Name;
        proxy.Value = metaData.Value;
    });
    

    我认为这涵盖了所有基础:)

    【讨论】:

    • 万岁乔恩国王..+1。一个简单的问题,我喜欢使用 List,然后使用 ToArray() 返回。我喜欢使用列表,因为我不喜欢使用像 i 这样的索引。我这样做是在扼杀表演吗?
    • 嗯,你正在损害性能,但可能不会显着。如果我从数组 转换为 数组,我可能不会通过列表,但一旦对最终结果的长度有任何疑问,我将使用列表以方便起见.不过不要忘记 Array.ConvertAll :)
    • 哇!!小费罐在哪里!你是个圣人,能像这样帮助我真是太好了。我学习缓慢,非常感谢您的帮助。
    • 哎呀..解决了上面讨论的编译问题,现在我无法构建代理类,因为:TRIMBrokerUtil.MetaData 无法序列化,因为它没有无参数的构造函数。
    • 这很容易 - 给它一个无参数的构造函数:)
    【解决方案2】:

    我只会使用 LINQ 来执行此操作:

    TRIMBrokerASMXProxy.ASMXProxy.MetaData[] kvData =
        metaDataArray.Select(d => 
            new TRIMBrokerASMXProxy.ASMXProxy.MetaData(
                d.Name, d.Value)).ToArray();
    

    此外,如果您使用的是 .NET 3.5,这意味着您也可以使用 WCF,这就是您应该用来生成代理的东西。您可以将您的 TRIMBrokerASMXProxy.ASMXProxy.MetaData 类型与 DataContract 属性和被序列化的成员属性与 DataMember 属性。然后,您将能够使用实际类型定义您的合同,而根本不必执行转换。

    【讨论】:

    • 我也会,但我不确定我是否会向 C# 菜鸟建议,尤其是当我们不知道他是否使用 .NET 3.5 时 :)
    • 在 SO 提示发布新答案之前,我刚刚输入了完全相同的代码 :) +1
    • @Jon 可能会给新手动力,让他们跟上进度:)
    • @Jon:这就是两个不同答案的美妙之处,我们可以让“新秀”(你的名字,不是我的名字)来决定。
    • 不是我的指定 - OP 的:“作为 C# 的新手,我仍在为这个简单的任务而苦苦挣扎。”我用另一种可能性扩展了我的答案,它比普通的 LINQ(和 .NET 2.0 中)稍微高效一些 - Array.ConvertAll。
    【解决方案3】:

    您也可以使用 Array.ConvertAll。我知道你对此比较陌生,所以让我试着解释一下。它有 2 个通用参数。第一个是它想要转换的数组的类型(我们称之为 I)。第二个是您要转换的类型(我们称之为 O)。它接受一个类型为 I 的数组并返回一个类型为 O 的数组。第二个参数是一个 Converter 委托。应用我们有它的签名的命名就像这样。

    delegate O Converter(I input);
    

    委托的主体必须包含进行转换所需的代码。在 ConvertAll 函数中,代码遍历输入数组中的每个值,然后传递给委托。然后将委托返回的值存储到输出数组中。转换完所有值后,将输出数组返回给用户。

    using ProxyMetaData = TRIMBrokerASMXProxy.ASMXProxy.MetaData;
    
    ProxyMetaData[] convertedArray = Array.ConvertAll<MetaData, ProxyMetaData>(utilArray, 
    delegate(MetaData metaData)
    {
        ProxyMetaData returnValue = new ProxyMetaData();
        returnValue.Name = metaData.Name;
        returnValue.Value = metaData.Value;
        return returnValue;
    });
    

    【讨论】:

    • 谢谢杰克。这是有道理的,我会尝试,但是使用 Jon 的方法,我在尝试重建代理类时遇到了另一个转折:TRIMBrokerUtil.MetaData 无法序列化,因为它没有无参数构造函数但我需要一个带有 2 个参数的构造函数; 1 表示名称,1 表示值
    • 如果我理解正确,我也会在使用 Array.ConvertAll 时遇到同样的问题。我想我可能遇到了一个“更大”的问题??
    猜你喜欢
    • 2013-08-18
    • 2014-06-18
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 2021-07-03
    相关资源
    最近更新 更多