2009-07-17 7 views
0

OK J'ai une classe statique qui a deux membres statiques, une chaîne et un booléen.
Une méthode statique publique affecte des valeurs à ces membres en fonction de l'état des paramètres passés.Le membre statique ne conserve pas la valeur affectée

Une méthode statique privée est ensuite appelée pour traiter les membres statiques. Le problème est que, bien que le booléen conserve la valeur à laquelle il est défini dans la fonction publique, la chaîne ne le fait pas; il revient par défaut à sa valeur initialisée. Pourquoi est-ce?
Le code simplifié est ci-dessous.

static class MessageHandler 
{ 
    private static String m_messageToSend = String.Empty; 
    private static bool m_requiresACK = false; 


    public static void Send(String message) 
    { 
     //formatting etc (actual method sets more fields) 
     m_messageToSend = message; 
     m_requiresACK = true; 

     Send(); 
    } 

    private void static Send() 
    { 
     SendMessageDelegate sendDelegate = DoSend; 
     //At this point m_requiresACK remains true but m_messageToSend does not 
     //hold value of message; it is empty. 
     IAsyncResult ar = sendDelegate.BeginInvoke(m_messageToSend, m_requiresACK); 


     //rest of function 
    } 
} 

//some other class 
MessageHandler.Send("Hello"); 
+0

Vous êtes sûr d'être correctement affecté à la méthode Send (string). Avez-vous oublié de mentionner quoi que ce soit lors de la simplification du code tge? –

+1

Pourquoi est-ce une classe statique du tout? – devio

+0

Devio- peut-être que ça ne devrait pas être, je continue d'apprendre. Cela semblait être la solution la plus élégante et ne nécessitait pas la création d'un objet. Le nom de la classe n'est pas très bon et doit changer - MessageHandler peut-être parce qu'il les transmet. MessageHandler.Send (Message). – Kildareflare

Répondre

4

Le thread "unsafetyness" de ce code pourrait être le problème, puisque d'autres threads pourraient appeler Send (chaîne) alors que votre thread est actuellement au milieu de la même méthode. Je suggère la réécriture suivante de la classe Message:

static class Message 
{ 
    public static void Send(String message) 
    { 
     Send(message, true); 
    } 

    private void static Send(string messageToSend, bool requiresACK) 
    { 
     SendMessageDelegate sendDelegate = DoSend; 
     IAsyncResult ar = sendDelegate.BeginInvoke(messageToSend, requiresACK); 

     //rest of function 
    } 
} 
+0

Peter - cela semble avoir résolu le problème. En fait, j'ai utilisé des membres directement depuis que je me suis récemment penché vers cela plutôt que de passer en charge de nombreux paramètres (il y a en fait plus que répertorié). Cependant, bien sûr, dans cet exemple, il semblerait plus logique de transmettre des paramètres - des chevaux pour les cours. – Kildareflare

+0

Les variables membres sont généralement correctes, mais les variables de membre statiques nécessitent une attention particulière en matière de sécurité des threads. Heureux qu'il a réglé le problème. –

2

Ceci est probablement dû à un autre thread appelant

Message.Send(""); 

ou votre AppDomain est déchargé. Sans plus d'informations, il est difficile de dire avec certitude.

0

Je serais très surpris si un champ gardait la même valeur, et l'autre pas.

S'il s'agit d'une application Web, cela peut se produire si l'application est recyclée.

2

Vous avez d'énormes problèmes de sécurité de thread là. Si vous voulez vraiment cette statique, il y a une solution insolente:

[ThreadStatic] 
private static String m_messageToSend = String.Empty; 
[ThreadStatic] 
private static bool m_requiresACK = false; 

Cela agit maintenant comme statique, mais est par thread. Crise évitée; mais c'est un peu ... eh bien, j'essaierais d'éviter le besoin, moi-même - mais ça marchera bien.

important: les initialisateurs sont par fil, pas par demande; Comme il est probable que vos threads seront réutilisés, assurez-vous d'initialiser l'état avant de l'utiliser, sinon vous pourriez avoir de vieilles ordures.

+0

Cela ne sera appelé que sur un fil à la fois mais merci pour le conseil! J'avais une méthode d'initialisation mais je l'ai supprimée pour réduire le code. – Kildareflare

0

Je vois dans vos commentaires qu'après cette première ligne, la variable privée est vide au lieu de contenir la valeur du paramètre. Est-ce vrai dès que vous appuyez sur la première ligne de Send()?

Écrire un test d'unité ou un faisceau de test simple qui appelle Message.Send ("Hello World"); et fait une affirmation sur la sortie. L'isoler de votre base de code appelante pourrait faire la lumière si c'est votre classe de message qui se comporte anormalement, ou si c'est un consommateur envoyant des données mauvaises/inattendues. De même, à moins que votre // reste de la fonction n'inclue la réinitialisation de votre booléen, il sera toujours vrai après l'envoi du premier message.

+0

En l'occurrence, le booléen est réinitialisé - il y a aussi beaucoup d'autres formes et logique. J'ai beaucoup simplifié le code pour qu'il se concentre uniquement sur les problèmes que je rencontrais. Je pense qu'à l'avenir j'ajouterai plus de commentaires pour mettre en évidence ceci ... bien repéré bien. – Kildareflare

+0

Compris, et un peu attendu. Je viens d'ajouter cela comme un hasard que ce n'était pas réinitialisé. De temps en temps, le fruit le plus bas fonctionne. –

Questions connexes