Question

Je rencontre un problème inhabituel dans mes tests unitaires. La classe que je teste crée une propriété de dépendance de manière dynamique au moment de l'exécution et le type de cette propriété de dépendance peut varier en fonction des circonstances. Lors de l'écriture de mes tests unitaires, je dois créer la propriété de dépendance avec différents types, ce qui entraîne des erreurs car vous ne pouvez pas redéfinir une propriété de dépendance existante.

Existe-t-il un moyen de désenregistrer une propriété de dépendance ou de modifier le type d'une propriété de dépendance existante?

Merci!

OverrideMetadata () ne vous permet de modifier que très peu de choses, comme la valeur par défaut, afin que cela ne soit pas utile. L’approche AppDomain est une bonne idée et peut fonctionner, mais elle semble plus compliquée que ce que je voulais vraiment approfondir pour le test des unités.

Je n'ai jamais trouvé le moyen d'annuler l'enregistrement d'une propriété de dépendance. J'ai donc réorganisé et réorganisé avec soin mes tests unitaires pour éviter le problème. Je reçois un peu moins de tests, mais comme ce problème ne se poserait jamais dans une application réelle et que je ne vivrais que lors des tests unitaires.

Merci pour l'aide!

Était-ce utile?

La solution

J'avais un problème similaire hier encore lorsque j'ai essayé de tester ma propre classe de création DependencyProperty. Je suis tombé sur cette question et j'ai remarqué qu'il n'y avait pas de solution réelle pour annuler les propriétés de dépendance. J'ai donc creusé avec le réflecteur Red Gate .NET pour voir ce que je pouvais trouver. avec.

En regardant les DependencyProperty.Register surcharges, elles semblaient toutes pointer vers DependencyProperty.RegisterCommon. Cette méthode comporte deux parties:

Tout d'abord pour vérifier si la propriété est déjà enregistrée

FromNameKey key = new FromNameKey(name, ownerType);
lock (Synchronized)
{
  if (PropertyFromName.Contains(key))
  {
    throw new ArgumentException(SR.Get("PropertyAlreadyRegistered", 
      new object[] { name, ownerType.Name }));
  }
}

Deuxièmement, enregistrer le DependencyProperty

DependencyProperty dp = 
  new DependencyProperty(name, propertyType, ownerType, 
    defaultMetadata, validateValueCallback);

defaultMetadata.Seal(dp, null);
//...Yada yada...
lock (Synchronized)
{
  PropertyFromName[key] = dp;
}

Les deux éléments sont centrés autour de DependencyProperty.PropertyFromName, une table de hachage. J'ai aussi remarqué le DependencyProperty.RegisteredPropertyList, un ItemStructList<DependencyProperty> mais je n'ai pas vu où il est utilisé. Cependant, pour des raisons de sécurité, j’ai pensé que j’essayerais d’en retirer autant que possible.

Je me suis donc retrouvé avec le code suivant qui m'a permis de & "désinscrire &"; une propriété de dépendance.

private void RemoveDependency(DependencyProperty prop)
{
  var registeredPropertyField = typeof(DependencyProperty).
    GetField("RegisteredPropertyList", BindingFlags.NonPublic | BindingFlags.Static);
  object list = registeredPropertyField.GetValue(null);
  var genericMeth = list.GetType().GetMethod("Remove");
  try
  {
    genericMeth.Invoke(list, new[] { prop });
  }
  catch (TargetInvocationException)
  {
    Console.WriteLine("Does not exist in list");
  }

  var propertyFromNameField = typeof(DependencyProperty).
    GetField("PropertyFromName", BindingFlags.NonPublic | BindingFlags.Static);
  var propertyFromName = (Hashtable)propertyFromNameField.GetValue(null);

  object keyToRemove = null;
  foreach (DictionaryEntry item in propertyFromName)
  {
    if (item.Value == prop)
      keyToRemove = item.Key;
  }
  if (keyToRemove != null)
  propertyFromName.Remove(keyToRemove);
}

Cela a fonctionné assez bien pour que je puisse exécuter mes tests sans obtenir un & "déjà enregistré &"; exception. Cependant, je vous recommande vivement de ne pas utiliser cette méthode dans aucun type de code de production. Il existe probablement une raison pour laquelle MSFT a choisi de ne pas disposer d'un moyen formel pour annuler l'enregistrement d'une propriété de dépendance, et d'essayer d'aller à l'encontre de c'est juste demander des ennuis.

Autres conseils

Si tout échoue, vous pouvez créer un nouveau domaine d'application pour chaque test.

Je ne pense pas que vous puissiez annuler l'enregistrement d'une propriété de dépendance, mais vous pouvez la redéfinir en surchargeant les métadonnées comme suit:

MyDependencyProperty.OverrideMetadata(typeof(MyNewType), 
                     new PropertyMetadata());

Si nous enregistrons le nom d'une étiquette comme celle-ci:

Label myLabel = new Label();
this.RegisterName(myLabel.Name, myLabel);

Nous pouvons facilement annuler l’enregistrement du nom en utilisant:

this.UnregisterName(myLabel.Name);

Je faisais face à un scénario dans lequel j'ai créé un contrôle personnalisé qui hérite de Selector qui est censé avoir deux propriétés ItemsSource, HorizontalItemsSource et VerticalItemsSource.

Je n'utilise même pas la propriété ItemsControl et je ne veux pas que l'utilisateur puisse y accéder.

Je lis donc La grande réponse de statenjason , et ça m’a donné un énorme point de vue sur la façon de retirer un DP.
Cependant, mon problème était que, puisque j'avais déclaré le membre ItemsSourceProperty et le ItemsSource <<> (Private Shadows en C #), je ne pouvais pas le charger au moment de la conception, car private new ferait référence à variable ombrée.
De plus, lors de l’utilisation de la boucle mentionnée dans est ci-dessus (MyControlType.ItemsSourceProperty etc.), une exception a été émise indiquant que la collection a été modifiée au cours de l’itération.

Par conséquent, j’ai proposé une approche légèrement différente dans laquelle DependencyProperty est référencé en dur au moment de l’exécution, et la collection est copiée dans un tableau de sorte que rien n’a changé (VB.NET, excusez-moi):

Dim dpType = GetType(DependencyProperty)
Dim bFlags = BindingFlags.NonPublic Or BindingFlags.Static

Dim FromName = 
  Function(name As String, ownerType As Type) DirectCast(dpType.GetMethod("FromName",
    bFlags).Invoke(Nothing, {name, ownerType}), DependencyProperty)

Dim PropertyFromName = DirectCast(dpType.GetField("PropertyFromName", bFlags).
  GetValue(Nothing), Hashtable)

Dim dp = FromName.Invoke("ItemsSource", GetType(DimensionalGrid))
Dim entries(PropertyFromName.Count - 1) As DictionaryEntry
PropertyFromName.CopyTo(entries, 0)
Dim entry = entries.Single(Function(e) e.Value Is dp)
PropertyFromName.Remove(entry.Key)

Remarque importante: le code ci-dessus est entouré du constructeur partagé du contrôle personnalisé. Je n'ai pas à vérifier s'il est enregistré, car je sais qu'une sous-classe de Selcetor Fournit que foreach DictionaryEntry dp.

Avait un problème avec un ContentPresenter avec différents modèles de données où l'un d'entre eux avait un DependencyProperty avec un PropertyChangedCallback Lorsque vous modifiez le contenu de ContentPresenters en un autre DataTemplate, le rappel est conservé.

Dans l'événement UserControls Unloaded que j'ai appelé:

BindingOperations.ClearAllBindings(this);
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, new DispatcherOperationCallback(delegate { return null; }), null);

Cela a fonctionné pour moi

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top