Ecrire une enveloppe pour le IntPtr pourrait certainement travailler. Mais il n'est pas nécessaire que la mémoire reste valide tant que l'élément est stocké dans le dictionnaire. Si c'est le cas, le code client est beaucoup plus simple si vous créez votre propre répertoire, qui libère automatiquement la mémoire lorsqu'un élément est supprimé du dictionnaire. Pas besoin pour le client d'appeler Dispose() pour chaque item, c'est toujours un avantage.
Pour cela, dérivez votre propre classe de IDictionary<object, IntPtr>
et IDisposable. Vous pouvez simplement déléguer la plupart des appels de méthode à un dictionnaire privé. Vous aurez besoin d'un Add() personnalisé pour allouer la mémoire, Delete pour le libérer. Et implémentez Dispose() et le finaliseur pour nettoyer. Le code est un peu laid si:
class MyDictionary : IDictionary<object, IntPtr>, IDisposable {
private Dictionary<object, IntPtr> impl = new Dictionary<object, IntPtr>();
public void Add(object key) {
IntPtr mem = Marshal.AllocCoTaskMem(666); // Something smarter here...
impl.Add(key, mem);
}
public bool Remove(object key) {
if (!impl.ContainsKey(key)) return false;
Marshal.FreeCoTaskMem(impl[key]);
return impl.Remove(key);
}
protected void Dispose(bool disposing) {
foreach (IntPtr mem in impl.Values) Marshal.FreeCoTaskMem(mem);
if (disposing) impl.Clear();
}
public void Dispose() {
Dispose(true);
}
~MyDictionary() {
Dispose(false);
}
// Boilerplate
public void Add(object key, IntPtr value) { throw new NotImplementedException(); }
public void Add(KeyValuePair<object, IntPtr> item) { throw new NotImplementedException(); }
public bool Remove(KeyValuePair<object, IntPtr> item) { throw new NotImplementedException(); }
public bool ContainsKey(object key) { return impl.ContainsKey(key); }
public ICollection<object> Keys { get { return impl.Keys; }}
public bool TryGetValue(object key, out IntPtr value) { return impl.TryGetValue(key, out value); }
public ICollection<IntPtr> Values { get {return impl.Values; }}
public IntPtr this[object key] { get { return impl[key]; } set { impl[key] = value; } }
public void Clear() { impl.Clear(); }
public bool Contains(KeyValuePair<object, IntPtr> item) { return impl.Contains(item); }
public void CopyTo(KeyValuePair<object, IntPtr>[] array, int arrayIndex) { (impl as ICollection<KeyValuePair<object, IntPtr>>).CopyTo(array, arrayIndex); }
public int Count { get { return impl.Count; }}
public bool IsReadOnly { get { return (impl as ICollection<KeyValuePair<object, IntPtr>>).IsReadOnly; } }
public IEnumerator<KeyValuePair<object, IntPtr>> GetEnumerator() { return impl.GetEnumerator(); }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return (impl as System.Collections.IEnumerable).GetEnumerator(); }
}
AllocCoTaskMem est le meilleur allocateur BTW, il n'a pas le bagage hérité.
La meilleure solution consiste à ne pas allouer de mémoire non managée en premier lieu. C'est seulement là pour certains scénarios p/Invoke, et p/Invoke n'est pas mentionné dans la description de votre problème.Puisque vous allouez et libérez la mémoire, il semble peu probable que vous ayez besoin de le faire. –
Mon nouveau thread juste en passant ce slot alloué de la mémoire à exporter de la fonction kernel32.dll. Quand cette fonction se termine, je vais libérer cette fente. –