7

I'm doing a simple Entity change logging for our application. One question that arises is that while the enumeration values for DbEntityEntry.State property are clearly mutually exclusive (See MSDN), it is defined with Flags attribute and the values are chosen as if they can be combined.

Is it safe to assume that the values are mutually exclusive? Why did they choose this path?

Alireza
  • 5,421
  • 5
  • 34
  • 67

2 Answers2

4

Is it safe to assume that the values are mutually exclusive?

If you are planning for future compatibility, then no. The authors might add a value which could be combined with one of the current values to cover a wider state. You are better off masking.

They might not, but being defined this way leaves that option open.

Why did they chose this path?

Perhaps, so that people wouldn't assume that the values are mutually exclusive.

Mostly, it allows one to do mask tests that cover more than one value in a single test:

if (state & (EntityState.Deleted | EntityState.Modified | EntityState.Added) != 0)  …

This works because the values for the enum uses a flag layout style where each has different bits set (or is deliberately defined in terms of another):

Detached = 1,
Unchanged = 2,
Added = 4,
Deleted = 8,
Modified = 16

Because of this, EntityState.Deleted | EntityState.Modified | EntityState.Added has a value of 8 | 16 | 4 which is 28. It would not work if the values where just incremented:

Detached = 1,
Unchanged = 2,
Added = 3,
Deleted = 4,
Modified = 5

Now EntityState.Deleted | EntityState.Modified | EntityState.Added would have a value of 7 which is the same as EntityState.Detached | Entity.Unchanged | Entity.Deleted.

The FlagsAttribute is used to provide metadata indicating you are taking the former approach rather than the latter, so masking can work. The only effect it has directly on the type itself is in how ToString() works, which is to provide a value more meaningful when taking this approach than not.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 1
    According to @CodeCaster, it's not the `[Flags]` attribute that "allows one to do mask tests" (http://stackoverflow.com/questions/8447/what-does-the-flags-enum-attribute-mean-in-c). – haim770 Oct 01 '15 at 10:20
  • @haim770 it's not. It's the flag-style layout that allows that. `[Flags]` marks an enum as making use of a flag-style layout. – Jon Hanna Oct 01 '15 at 10:44
  • 1
    @JonHanna Can you elaborate on flag-style layout? Or a link will be appreciated. – Alireza Oct 01 '15 at 11:13
1

Internally, EntityState is also used to include/exclude more than one state.

For example, in ObjectStateManager:

IEnumerable<IEntityStateEntry> IEntityStateManager.GetEntityStateEntries(EntityState state)

Usage in ObjectContext:

var entriesAffected = ObjectStateManager.GetObjectStateEntriesCount(EntityState.Added |                   
                                                                    EntityState.Deleted |
                                                                    EntityState.Modified);

From API-consuming-point-of-view, I think you can safely assume that the actual state of an entity can only be one of the options.

haim770
  • 48,394
  • 7
  • 105
  • 133
  • 1
    _"For that [Flags] is required."_ - nope, the [only use for `[Flags]` is for printing an enum's value](http://stackoverflow.com/questions/8447/what-does-the-flags-enum-attribute-mean-in-c). It's purely metadata. – CodeCaster Oct 01 '15 at 10:15
  • 1
    @CodeCaster, Well, it is not *required* almost anywhere you're using a mask with Enum. But in this case (and in almost all other cases) it's there for that reason. – haim770 Oct 01 '15 at 10:18
  • @CodeCaster I was surprised to see that Flags is not required for that, and a quick sample application verifies your point. Just that in VS2015, I get intellisense warnings for doing "Bitwise Operations on enum not marked with Flags attribute". Thanks – Alireza Oct 01 '15 at 10:25
  • You get that warning because it was probably either not a good idea for you to use that enum as a set of flags, or else not a good idea for the author not to add metadata indicating it should be used as a set of flags (which is what `[Flags]` does). The "probably" above is why that's a warning, not an error. – Jon Hanna Oct 01 '15 at 10:46