2009-08-26 9 views
1

Je cherche un moyen de trier une liste d'objet (de tout type possible) afin que quoiqu'il arrive aux objets, tant qu'ils ne sont pas détruits, l'ordre garde le même (donc le hashCode n'est pas une bonne idée car dans certaines classes ça change au fil du temps), pour cette raison je pensais utiliser l'adresse de l'objet dans la mémoire mais je ne suis pas sûr que ça garde toujours le même L'adresse peut-elle être modifiée par un appel de collecte des ordures par exemple?). Cependant je cherche des propriétés d'objets (de n'importe quel type) qui resteront les mêmes tant que l'objet n'est pas détruit. Y en a-t-il? Et si oui, quels sont-ils?propriétés immutables d'un objet en C#

+0

Vous ne savez pas exactement ce que vous recherchez, ne pourriez-vous pas simplifier la création d'un tableau contenant une référence d'identifiant pour les objets. Ensuite, il suffit que les objets soient responsables de l'ajout d'eux-mêmes quand ils sont créés, et qu'ils prennent eux-mêmes de la liste quand ils sont détruits? – Darknight

+0

Votre question semble quelque peu étrange, et peut-être que si vous essayez d'expliquer le problème que vous essayez de résoudre, vous obtiendrez des réponses qui évitent le problème auquel vous êtes actuellement confronté. Pour répondre à l'une de vos questions: Les objets .NET sont déplacés en mémoire lors de la récupération de place, mais dans le monde géré, vous ne devez jamais utiliser d'adresse d'objet. –

+0

Je veux le même ordre pour chaque tableau d'objets, donc si vous faites une copie de la liste (pas une copie profonde, une copie des références aux objets) et que vous mélangez le second tableau, vous pouvez facilement le faire dans le bon ordre à cause de la poperté immuable. Une certaine valeur qui peut être accédée et qui assure un certain ordre pour chaque objet à evry objet, qui ne dépend pas du contenu de l'objet lui-même. –

Répondre

2

Oui, les objets peuvent être déplacés en mémoire par le garbage collector, à moins que vous ne le demandiez spécifiquement (et il est généralement recommandé de laisser le GC faire sa chose).Ce dont vous avez besoin ici est une table d'appoint: créez un dictionnaire avec les objets eux-mêmes, et pour la valeur mettez tout ce que vous voulez (peut être le hashcode original de l'objet, ou même un nombre aléatoire). Lorsque vous trier, trier par cette touche latérale. Maintenant si par exemple l'objet a a la valeur "1" dans ce dictionnaire, il sera toujours trié en premier - indépendamment des modifications apportées à a, parce que vous regarderez dans votre dictionnaire de côté pour la clé et le code pour un ne sait pas y aller et le changer (et bien sûr vous prenez soin de garder ces données immuables). Vous pouvez utiliser weak references pour vous assurer que vos entrées de dictionnaire disparaissent s'il n'y a pas d'autre référence à l'objet a.

0

Le tri par adresse mémoire n'est bien sûr possible que des objets de référence. Donc, tous les types ne peuvent pas être triés de cette façon, les types primitifs et les structures ne le sont pas. L'autre façon est de dépendre d'une certaine interface, où vous avez besoin que chacune de ces instances peut retourner un Guid. Ceci est créé dans le constructeur et non modifié.

public interface ISortable 
{ 
    Guid SortId { get; } 
} 

class Foo : ISortable 
{ 
    Foo() 
    { 
    SortId = Guid.NewGuid(); 
    } 
    Guid SortId { get; private set; } 
} 

L'avantage d'un guid est qu'il peut être créé indépendamment dans chaque classe. Vous n'avez pas besoin de synchronisation, vous donnez simplement un identifiant à chaque classe. A propos: Si vous utilisez les objets dans un dictionnaire comme clé, ils ne doivent pas changer leur code de hachage. Ils doivent être immuables. Cela pourrait probablement être une contrainte sur laquelle vous pourriez compter.


Edit: vous pouvez écrire votre liste spécialisée qui est capable de garder ordonnancements.

Soit vous stockez l'ordre d'origine lorsque la liste est créée à partir d'une autre liste, puis vous pouvez restaurer l'ordre à tout moment. De nouveaux objets pourraient être mis à la fin. (y at-il de nouveaux éléments quand même?)

Ou vous faites quelque chose de plus sophistiqué et stockez l'ordre de n'importe quel objet qui a déjà été vu par votre classe de liste dans une mémoire statique. Ensuite, vous pouvez trier toutes les listes indépendamment. Mais méfiez-vous des références que vous tenez, ce qui évitera que les objets soient nettoyés par le GC. Vous aurez besoin de références hebdomadaires, je pense qu'il y a des références faibles en C# mais je ne les ai jamais utilisées.

Encore mieux serait de mettre cette logique dans une classe de tri. Cela fonctionne donc pour toutes les listes triées par votre classe de tri.

1

Mis à jour compte tenu des détails ajoutés à la question (commentaires); il suffit de prendre une copie du contenu de la liste avant de le trier ...


L'adresse n'est pas corrigée. Et pour les objets arbitraires, non, il n'y a pas de manière sensée de le faire. Pour vos propres objets que vous pouvez ajouter quelque chose de commun, comme:

interface ISequence { int Order { get; } } 
static class Sequence { 
    private static int next; 
    public static int Next() { 
     return Interlocked.Increment(ref next); } 
} 
class Foo : ISequence { 
    private readonly int sequence; 
    int ISequence.Order { get { return sequence; } } 
    public Foo() { 
     sequence = Sequence.Next(); 
    } 
} 

Un peu décousu, mais il faut travailler, et peut être utilisé dans une base de classe. Le Order est maintenant non-changeant et séquentiel. Mais seulement AppDomain -specific, et toutes les API de sérialisation ne le respecteront pas (vous devrez utiliser des callbacks de sérialisation pour initialiser la séquence dans de tels cas).

Questions connexes