gpt4 book ai didi

c# - 复制 KeyedCollection 的最快方法

转载 作者:行者123 更新时间:2023-12-03 17:11:26 24 4
gpt4 key购买 nike

我正在开发一个 C# 对象复制构造函数,其中一部分涉及将 KeyedCollection 的内容复制到新的 KeyedCollection 中。这是我目前实现的:

class MyKeyedCollection : KeyedCollection<uint, DataObject>
{
protected override uint GetKeyForItem( DataObject do )
{
return do.Key;
}
}

class MyObject
{
private MyKeyedCollection kc;

// Copy constructor
public MyObject( MyObject that )
{
this.kc = new MyKeyedCollection();
foreach ( DataObject do in that.kc )
{
this.kc.Add( do );
}
}
}

这做了正确的事情——集合被按预期复制。问题是它也有点慢。我猜测问题在于每个 .Add(do) 都需要对现有数据进行唯一性检查,即使我知道它来自保证唯一性的来源。

如何使这个复制构造函数尽可能快?

最佳答案

好的,有一点不安全代码的解决方案怎么样?只是为了好玩?

警告!这是针对 Windows 操作系统和 32 位进行编码的,但没有理由不能修改此技术以适用于 64 位或其他操作系统。最后我在3.5框架上进行了测试。我认为它可以在 2.0 和 3.0 上运行,但我没有测试。如果雷蒙德在修订版或补丁之间更改了实例变量的数量、类型或顺序,那么这将不起作用。

但是这很快!!!

这会侵入 KeyedCollection、其底层 List<> 和 Dictionary<> 并复制所有内部数据和属性。这是一个黑客,因为要做到这一点,你必须访问私有(private)内部变量。我基本上为 KeyedCollection、List 和 Dictionary 制作了一些结构,它们是这些类的私有(private)变量,按正确的顺序排列。我只是将这些结构指向类所在的位置,瞧...您可以弄乱私有(private)变量!我使用 RedGate 反射器来查看所有代码在做什么,这样我就可以找出要复制的内容。然后只需复制一些值类型并在几个地方使用 Array.Copy 即可。

结果是CopyKeyedCollection<,>、CopyDict<>和CopyList<>。免费获得快速复制字典<>的功能和快速复制列表<>的功能!

在解决这个问题时我注意到的一件事是 KeyedCollection 包含一个列表和一个字典,它们都指向相同的数据!我一开始认为这很浪费,但评论者指出 KeyedCollection 明确适用于同时需要有序列表和字典的情况。

无论如何,我是一名汇编/C 程序员,被迫使用了一段时间的 vb,所以我并不害怕做这样的 hack。我是 C# 新手,所以请告诉我我是否违反了任何规则或者您是否认为这很酷。

顺便说一句,我研究了垃圾收集,这应该可以很好地与 GC 配合使用。我认为如果我添加一些代码来修复我们用于复制的毫秒的内存,那将是谨慎的做法。你们告诉我吧。如果有人要求的话我会添加一些评论。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections.ObjectModel;
using System.Reflection;

namespace CopyCollection {

class CFoo {
public int Key;
public string Name;
}

class MyKeyedCollection : KeyedCollection<int, CFoo> {
public MyKeyedCollection() : base(null, 10) { }
protected override int GetKeyForItem(CFoo foo) {
return foo.Key;
}
}

class MyObject {
public MyKeyedCollection kc;

// Copy constructor
public MyObject(MyObject that) {
this.kc = new MyKeyedCollection();
if (that != null) {
CollectionTools.CopyKeyedCollection<int, CFoo>(that.kc, this.kc);
}
}
}

class Program {

static void Main(string[] args) {

MyObject mobj1 = new MyObject(null);
for (int i = 0; i < 7; ++i)
mobj1.kc.Add(new CFoo() { Key = i, Name = i.ToString() });
// Copy mobj1
MyObject mobj2 = new MyObject(mobj1);
// add a bunch more items to mobj2
for (int i = 8; i < 712324; ++i)
mobj2.kc.Add(new CFoo() { Key = i, Name = i.ToString() });
// copy mobj2
MyObject mobj3 = new MyObject(mobj2);
// put a breakpoint after here, and look at mobj's and see that it worked!
// you can delete stuff out of mobj1 or mobj2 and see the items still in mobj3,
}
}

public static class CollectionTools {

public unsafe static KeyedCollection<TKey, TValue> CopyKeyedCollection<TKey, TValue>(
KeyedCollection<TKey, TValue> src,
KeyedCollection<TKey, TValue> dst) {

object osrc = src;
// pointer to a structure that is a template for the instance variables
// of KeyedCollection<TKey, TValue>
TKeyedCollection* psrc = (TKeyedCollection*)(*((int*)&psrc + 1));
object odst = dst;
TKeyedCollection* pdst = (TKeyedCollection*)(*((int*)&pdst + 1));
object srcObj = null;
object dstObj = null;
int* i = (int*)&i; // helps me find the stack

i[2] = (int)psrc->_01_items;
dstObj = CopyList<TValue>(srcObj as List<TValue>);
pdst->_01_items = (uint)i[1];

// there is no dictionary if the # items < threshold
if (psrc->_04_dict != 0) {
i[2] = (int)psrc->_04_dict;
dstObj = CopyDict<TKey, TValue>(srcObj as Dictionary<TKey, TValue>);
pdst->_04_dict = (uint)i[1];
}

pdst->_03_comparer = psrc->_03_comparer;
pdst->_05_keyCount = psrc->_05_keyCount;
pdst->_06_threshold = psrc->_06_threshold;
return dst;
}

public unsafe static List<TValue> CopyList<TValue>(
List<TValue> src) {

object osrc = src;
// pointer to a structure that is a template for
// the instance variables of List<>
TList* psrc = (TList*)(*((int*)&psrc + 1));
object srcArray = null;
object dstArray = null;
int* i = (int*)&i; // helps me find things on stack

i[2] = (int)psrc->_01_items;
int capacity = (srcArray as Array).Length;
List<TValue> dst = new List<TValue>(capacity);
TList* pdst = (TList*)(*((int*)&pdst + 1));
i[1] = (int)pdst->_01_items;
Array.Copy(srcArray as Array, dstArray as Array, capacity);

pdst->_03_size = psrc->_03_size;

return dst;
}

public unsafe static Dictionary<TKey, TValue> CopyDict<TKey, TValue>(
Dictionary<TKey, TValue> src) {

object osrc = src;
// pointer to a structure that is a template for the instance
// variables of Dictionary<TKey, TValue>
TDictionary* psrc = (TDictionary*)(*((int*)&psrc + 1));
object srcArray = null;
object dstArray = null;
int* i = (int*)&i; // helps me find the stack

i[2] = (int)psrc->_01_buckets;
int capacity = (srcArray as Array).Length;
Dictionary<TKey, TValue> dst = new Dictionary<TKey, TValue>(capacity);
TDictionary* pdst = (TDictionary*)(*((int*)&pdst + 1));
i[1] = (int)pdst->_01_buckets;
Array.Copy(srcArray as Array, dstArray as Array, capacity);

i[2] = (int)psrc->_02_entries;
i[1] = (int)pdst->_02_entries;
Array.Copy(srcArray as Array, dstArray as Array, capacity);

pdst->_03_comparer = psrc->_03_comparer;
pdst->_04_m_siInfo = psrc->_04_m_siInfo;
pdst->_08_count = psrc->_08_count;
pdst->_10_freeList = psrc->_10_freeList;
pdst->_11_freeCount = psrc->_11_freeCount;

return dst;
}

// these are the structs that map to the private variables in the classes
// i use uint for classes, since they are just pointers
// statics and constants are not in the instance data.
// I used the memory dump of visual studio to get these mapped right.
// everything with a * I copy. I Used RedGate reflector to look through all
// the code to decide what needed to be copied.
struct TKeyedCollection {
public uint _00_MethodInfo; // pointer to cool type info
// Collection
public uint _01_items; // * IList<T>
public uint _02_syncRoot; // object
// KeyedCollection
public uint _03_comparer; // IEqualityComparer<TKey>
public uint _04_dict; // * Dictionary<TKey, TItem>
public int _05_keyCount; // *
public int _06_threshold; // *
// const int defaultThreshold = 0;
}

struct TList {
public uint _00_MethodInfo; //
public uint _01_items; // * T[]
public uint _02_syncRoot; // object
public int _03_size; // *
public int _04_version; //
}

struct TDictionary {
// Fields
public uint _00_MethodInfo; //
public uint _01_buckets; // * int[]
public uint _02_entries; // * Entry<TKey, TValue>[]
public uint _03_comparer; // IEqualityComparer<TKey>
public uint _04_m_siInfo; // SerializationInfo
public uint _05__syncRoot; // object
public uint _06_keys; // KeyCollection<TKey, TValue>
public uint _07_values; // ValueCollection<TKey, TValue>
public int _08_count; // *
public int _09_version;
public int _10_freeList; // *
public int _11_freeCount; // *
}

}


}

关于c# - 复制 KeyedCollection 的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/984143/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com