2009-02-05 2 views
0

Si je mets une portée au niveau de l'ami sur un poseur, comme ça ...Après avoir restreint la portée de Setter, puis appliqué une interface, la portée n'est pas prise en compte!

Public Class MyClass 
    Public Property IsDirty() As Boolean 
     Get 
      Return _isDirty 
     End Get 
     Friend Set(ByVal trueFalse As Boolean) 
      _isDirty = trueFalse 
     End Set 
    End Property 
End Class 

... Et puis appelez d'un autre projet, il fonctionne correctement. Je ne peux pas faire quelque chose comme MyClass.IsDirty = True.

Parfait! C'est exactement ce que je veux.

Mais maintenant, si je définir une interface, et je ferai bien de le faire:

Public Interface IMyClass 
    Property IsDirty() As Boolean 
End Interface 

je peux faire quelque chose comme:

Dim MyInstance as IMyClass= GetSomeInstanceOfMyClass() 
MyInstance.IsDirty=True 

... Et, bizarrement, il fonctionne! Aucune exception n'est levée et la variable interne est définie sur True. Il ignore complètement la portée de l'ami!

C'est hideux. Qu'est-ce que je rate?? J'ai besoin de cela parce que je suis en train de concevoir une API, et je veux que l'API interne puisse définir IsDirty, mais les développeurs finaux ne devraient pas être capables de le faire. Actuellement, j'emballe toute la classe dans une façade pour obtenir cette fonctionnalité, mais la façade ne devrait pas être nécessaire.

Répondre

1

Les méthodes d'interface sont toujours accessibles au public. Vous ne pouvez pas corriger cela par une implémentation d'interface explicite, cela ne fera que masquer la méthode de classe. Le simple fait de convertir l'objet en type d'interface donne à nouveau un accès sans entrave.

EDIT: en fait, le problème est facile à résoudre. Il suffit de déclarer la propriété ReadOnly dans la déclaration d'interface :)

Par exemple:

Public Interface IMyClass 
    ReadOnly Property IsDirty() As Boolean 
End Interface 

Public Class Test 
    Implements IMyClass 
    Private mIsDirty As Boolean 
    Private ReadOnly Property IsDirtyImpl() As Boolean Implements IMyClass.IsDirty 
     Get 
      Return mIsDirty 
     End Get 
    End Property 
    Public Property IsDirty() As Boolean 
     Get 
      Return mIsDirty 
     End Get 
     Friend Set(ByVal value As Boolean) 
      mIsDirty = value 
     End Set 
    End Property 
End Class 
+0

Malédictions! Alors qu'est-ce que vous faites ici, enveloppez la classe dans une structure de style de façade et présentez cela au développeur final, tout en gardant la classe "normale" à usage interne? –

+0

Je ferais probablement la propriété ReadOnly comme le suggère nobugz, puis ajouterai un Friend Sub SetIsDirty (ByVal isDirty As Boolean) pour l'utilisation interne de l'API. – chyne

+0

BTW, déclarant que la propriété ReadOnly dans l'interface ne fonctionne pas, au moins dans VB. Il ne voit pas la propriété read/write sur la classe comme une correspondance. :/C'est l'une des parties les plus laides du cadre que j'ai rencontré. –

1

Ce qui vous manque, c'est le concept d'implémentation d'interface explicite et explicite. Voir the answer to this question for more details.

Et si vous pensez que c'est hideux avec un ami Setter, essayez de le définir en privé et regardez-le toujours accessible via l'interface!

+0

je l'ai fait. :) Lorsque l'ami n'a pas travaillé, je l'ai mis en privé. Je pensais que ma tête allait exploser. Merci pour l'aide. –

Questions connexes