12

从 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");

是否有 C# 类似的 C++ 函数emplace,例如emplace_back容器类 ( System.Collections.Generic.List)?

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

4

4 回答 4

6

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

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

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

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

于 2016-03-14T11:26:59.707 回答
4

您可以通过扩展来改进@Boo 变体您可以使用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));
    }
}

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

于 2016-03-14T15:14:45.703 回答
-1

在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");
于 2016-03-14T11:24:04.263 回答
-1

看来您有以下问题:

  1. 键入的时间更长"new S"。但"add"比 短"emplace"。通过智能感知为您添加类型(Enter键入后只需按"new "):


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

  2. 性能:见@Xanatos 答案

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

结论:我们不需要emplaceC#.

于 2016-03-14T12:22:38.520 回答