【问题标题】:Is there any C# analogue of C++11 emplace/emplace_back functions?是否有 C++11 emplace/emplace_back 函数的 C# 类似物?
【发布时间】:2016-06-29 09:19:33
【问题描述】:

从 C++11 开始,可以编写类似的东西

#include <vector>
#include <string>

struct S
{

    S(int x, const std::string& s)
        : x(x)
        , s(s)
    {
    }

    int x;
    std::string s;

};

// ...

std::vector<S> v;

// add new object to the vector v
// only parameters of added object's constructor are passed to the function
v.emplace_back(1, "t");

对于容器类 (System.Collections.Generic.List),是否有任何 C++ 函数的 C# 类似物,例如 emplaceemplace_back

更新: 在 C# 中,类似的代码可能会写成 list.EmplaceBack(1, "t"); 而不是 list.Add(new S(1, "t"));。最好不要记住类名并在这种情况下每次都写new ClassName

【问题讨论】:

  • 不是所有的 C# 对象总是动态分配的,基本上总是指针持有的吗?这样一个 emplace 功能会带来什么?
  • @Angew 对于struct 数据类型,它会稍微快一些。对于大的struct 数据类型,它可能会更快。但是struct 数据类型不应该很大,所以这将是一个寻找问题的解决方案:-)
  • @Angew 减少代码大小。使用 emplace,您无需在 C++ 中编写 v.insert(S(1, "t"));。在 C# 中,它可能写成 list.EmplaceBack(1, "t"); 而不是 list.Add(new S(1, "t"));
  • 如果你写C#实现并说明它有什么问题会更好。
  • 如果你觉得它对 C# 来说是一个有价值的特性,你可以随时在 connect.microsoft.com 添加特性请求。但是,如果它进入实现功能的最终列表,我会非常非常惊讶。已经有一种方法可以做到这一点,在 C# 存在的 17 年中很少有人抱怨必须键入类名,并且它在 C# 中没有实际用途(与 C++ 不同)。再加上设计、测试和文档的数量,可能远远超过感知到的好处。习惯输入类名...

标签: c# collections emplace


【解决方案1】:

一般来说,C# 中没有类似的东西,它的需求也比 C++ 少得多。

在 C# 中,当您拥有 List&lt;SomeReferenceType&gt; 时,您真正拥有的是 List&lt;ReferenceToSomeType&gt;,因此是一个引用列表,每个元素的大小为 4 或 8 个字节(请参阅 How big is an object reference in .NET?)。复制引用不会导致底层对象被复制,因此它非常快(您复制了大约 4 或 8 个字节,并且处理器针对此操作进行了优化,因为这是处理器的本机指针的大小)。因此,当您 someList.Add(someReference) 时,您正在做的是添加对您的 List&lt;&gt; 的引用。

在 C++ 中,当您拥有 std::vector&lt;SomeType&gt; 时,您拥有的是 SomeType 的向量,每个元素的大小等于 sizeof(SomeType)。在std::vector&lt;&gt; 中插入新元素将导致您插入的元素被复制(克隆、复制...选择您喜欢的动词)。这是一项昂贵的操作。

您经常使用的模式是创建一个对象只是为了将其插入std::vector&lt;&gt;。为了在 C++11 中优化此操作,他们添加了两种方法:std::vector&lt;&gt;::emplace 方法和移动语义的std::vector&lt;&gt; 支持。不同之处在于移动语义必须由SomeType 类型支持(您需要一个带有noexcept 说明符的移动构造函数),而每种类型都支持emplace(最终只使用放置构造函数)。

【讨论】:

  • 减少代码大小是必要的:假设EmplaceBack你不需要每次都在Add语句中写new ClassName
  • @Constructor:如果它在 C++ 中所做的只是为您节省一点打字,那么它就不会存在,因为这肯定不是它的动机之一。
  • @BenjaminLindley 当然,你是对的。但最好不要每次都在这种情况下写ClassName(C++)或new ClassName(C#)。
  • @Constructor 至少还有另一个原因是为什么在 C# 中它不太有用......想要这些坏东西。在 C# 中,将 DerivedType 的引用放在 BaseType 变量/容器中是完全可以的(这是一种常见的模式)。因此,拥有只能构建 BaseTypeList&lt;BaseType&gt;Emplace() 将不太有用。
  • @xanatos 是的,你是对的。但至少在 95% 的情况下,您将添加到您在列表声明中指定的相同类型的列表对象中,因此这样的函数可能足够有用。
【解决方案2】:

您可以通过扩展来改进@Boo variant
您可以使用Activator.CreateInstance 创建对象实例,从而使解决方案更加通用。

public static class ListExtension
{
    public static void Emplace<S>(this IList<S> list, params object[] parameters)
    {
        list.Add((S)Activator.CreateInstance(typeof(S), parameters));
    }
}

注意:没有检查类型和计数参数,所以如果你做错了,你会在运行时得到错误

【讨论】:

    【解决方案3】:

    在c#中你可以使用扩展方法来实现你想要的

    public static class ListExtension
    {
        public static void Emplace(this IList<S> list, int x, string s)
        {
            list.Add(new S(x, s));
        }
    }
    

    然后像这样使用它

    myList.Emplace(1,"t");
    

    【讨论】:

    • 并为我想成为集合成员的所有类的所有构造函数的所有重载编写这样的方法?我太懒了……
    • @Constructor,您可以使用反射创建对象实例,从而使解决方案更加通用
    • @Grundy 这怎么可能?
    • @Constructor,类似于public static void Emplace&lt;S&gt;(this IList&lt;S&gt; list, params object[] parameters){ list.Add((S)Activator.CreateInstance(typeof(S), parameters))}
    • @Grund 谢谢。您可以添加您的评论作为答案吗?
    【解决方案4】:

    您似乎有以下问题:

    1. "new S"输入的时间更长。但是"add""emplace" 短。类型由 intellisense 为您添加(输入 "new " 后只需按 Enter):


    1. 你害怕写错类型。那么你不能用List&lt;T&gt;。 Intellisense 将帮助您键入,并且编译器无论如何都不会允许在编译时添加错误的类型。

    2. 性能:见@Xanatos answer

    list.Add(new S(1, "t")); 非常好用。

    结论:C# 中不需要emplace

    【讨论】:

    • 一个简单的问题:为什么我需要输入任何可以通过智能(程序,而不是人类)添加的内容?做可以在 IDE/编译器级别自动化的事情不是程序员的工作。
    • 我不明白你的评论。你能举个例子来解释你的意思吗? Intellisense 不是人类,因此它只能在某些点提供帮助(例如,键入 . 将显示左侧可访问成员的列表)。可能自动化 emplace(使用pre-processor,例如VS扩展,这里不确定),但我没有看到一个有效的点为什么我想要它。
    • 您写道:“类型是由智能感知为您添加的。”如果智能感知足够聪明,可以添加类型,我为什么要自己做呢?它可以简单地在编译器级别完成。
    • 我现在明白你的意思了。我宁愿自己更喜欢add + new,即使有emplace 机制。错误/无聊的事情不断得到解决(参见C# 6.0)。你想要的那个非常小的东西会进入列表吗?我怀疑。
    猜你喜欢
    • 1970-01-01
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    • 1970-01-01
    相关资源
    最近更新 更多