Reverse engineering: representation of a C# Dictionary?

Viewed 130

I already have written my code, but for my personal knowledge I would like to know how could I have modelized it.

Here we go: an user can have many profiles, each one tied to one and only application. A profile defines user's rights within the application: same user can be administrator in the scope of app1, at the same time a basic user of app2...

Pseudo-code looks like that:

public class User
{
   public string UserId { get; set; }

   // Only store the AppId of application but it could be an IDictionary<Application, UserProfile>
   public IDictionary<string, UserProfile> Profiles { get; set; }
}

public enum UserProfile 
{
   BasicUser,
   Administrator,
}

public class Application
{
   public string AppId { get; set; }
}

As you can see UserProfile is just an enum, while Application could be a simple string but I need a class here.

How would I represent these 3 entities on a class diagram? I think that a class association is not a good option, as it wouldn't have any property. But I don't know what else is possible.

3 Answers

I don't see any n-ary association in your code.

What you sketched looks like this:

enter image description here

Application isn't associated to anything so its an orphan.

Properties can be represented in different ways and are language specfic. The above would be used for C#

Dictionaries matter !

At first I was thinking like qwerty_so, except that:

  • there is a qualified association with UserProfiles: it is implemented with with an IDictionary, where a string is used to qualify the User.
  • this association is navigable in one direction, since you can go easily from the User to UserProfile, but it's much more difficult to go the other way round (you can, but you have to iterate through all the uses).

So the diagram could look like:

enter image description here

Some additional remarks about this diagram:

  • There is no UML standard for C# properties, which are a mixture between an UML property and an UML operation (via the implicit getter and setter). The usual practice is to use an UML profile that defines the stereotype «property». My own preferred option is to keep it in the properties of the class (like here or here), since that is the semantic of a C# property. However, some argue that this stereotype should be considered as a specialisation of an UML operation (like here and in qwerty's answer), which is also a valid argument, especially if you define custom getters and setters.
  • Be careful with the multiplicity in qualified association, since it applies to the User qualified with the string. So 0..1 UserProfile is for one specific combination of User and string. So it is in reality 0..* if we would consider the unqualified User.

Model transformation

We have to keep in mind that a given implementation could correspond to different designs. The implementation is how you write the code, and the design is how you see the things.

So we can transform this first reversed engineered model to match your thought model. Only you can tell how you want to see the things that led you to your current implementation.

For example, you may not be so interested in navigability, and you may set the focus on the many-to-many association between the unqualified User and UserProfile. With this approach, the string that was used as qualifier would become a property of the association class:

enter image description here

Be aware nevertheless that it's a transformation. Qualified association and one-to-many is not the same thing and the two models do not mean exatly the same thing.

And here comes the n-ary association !

Now the key question is the purpose of the string property in this association class. I strongly suspect that it's in fact the id of your Application (I let you confirm in the comments).

If it's the case, we would have an association between the association class and the Application. And we could remove the string property from the association class because it would then be redundant.

But an association class that is itself associated with some other class, shows that there in fact an n-ary associaton (ternary here). So, we could make this explicit:

enter image description here

Now you have an n-ary association. You could even have an association class behind it, if there would be additional properties to associate with each triplet (User, Application, UserProfile).

But be aware that this diagram is less precise. It is for example more difficult to indicate navigability constraints in an n-ary association. And it does no longer fully correspond to your implementation: this model suggest that you could find users starting from an application, whereas in your implementation it's more difficult.

Conclusion/advices

Personally, I find n-ary association difficult to work with and I prefer to decompose them in a set of classes and binary associations (and association classes when necessary): This allows to remove a lot of ambiguity and gives tighter control. I can only recommend you the same approach.

Consider also your implementation: if the implementation represents your view of the world, then use the qualified association, because it's the UML equivalent to the dictionary.

However if the ternary association is your view of the world, you may sooner or later have to review your current implementation. Probably you'd extract the profiles to make an own class of it.

Your C# property User::Profiles implements a many-to-many association class between User and Application having a UML property like role: RoleEL, where I have replaced your enumeration name "UserProfile" with "RoleEL" for better readability (notice that "EL" stands for "enumeration literal"). This is shown in the following class diagram:

enter image description here

I think this design model is simpler and more natural than the models suggested by @qwerty_so and @Christophe.

Notice that the model by qwerty_so is not a (logical) design model, but rather an implementation model, as it does not display the relationship between User and Application, but rather keeps it burried in the code of the profiles property. Also, it unncessarily duplicates a UML property (using the confusing stereotype keyword «property»).

Related