Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does FxCop insist on IDisposable for a struct

Tags:

c#

fxcop

I have the code similar to the following in one of my projects:

internal enum ArtworkType
{
    Undefined = 0,
    Bmp = 1,
    Gif = 2,
    Jpeg = 3,
    Png = 4
}

[StructLayout(LayoutKind.Sequential)]
internal struct TagArtwork
{
    internal IntPtr data;
    internal int size;
    internal ArtworkType type;
}

When I run FxCop on this code, I get run into warning CA1049. This struct is used for interoperability with a native code library, so it pretty much has to have this layout. Why does FxCop give me grief about this struct? I have other structs in the same source file, which also have IntPtr members, but FxCop does not complain about those.

For example, the following code does not trigger the same warning:

internal enum ItemType
{
    Implicit = 0,
    Utf8 = 1,
    Utf16 = 2,
    Sjis = 3,
    Html = 6,
    Xml = 7,
    Uuid = 8,
    Isrc = 9,
    Mi3p = 10,
    Gif = 12,
    Jpeg = 13,
    Png = 14,
    Url = 15,
    Duration = 16,
    DateTime = 17,
    Genres = 18,
    Integer = 21,
    Riaa_pa = 24,
    Upc = 25,
    Bmp = 27,
    Undefined = 255
}

[StructLayout(LayoutKind.Sequential)]
internal struct MP4ItmfData
{
    internal byte typeSetIdentifier;
    internal ItemType typeCode;
    internal int locale;
    internal IntPtr value;
    internal int valueSize;
}

I suppose I could implement IDisposable on the struct, but that just seems wrong. Likewise, I could simply suppress the warning, but at the moment, I want to understand what it is about this particular struct that is triggering the warning, when it's not that much different than the other seven structs I have in the same source file. Alternatively, I'd happily accept an explanation of why the other structs don't trigger this warning.

like image 823
JimEvans Avatar asked Jan 16 '23 02:01

JimEvans


2 Answers

The Code Anylsis engine produces this warning any time you have a managed type that includes a member of what it considers a "native" type. To be a native type, the field must:

  • Be IntPtr, UIntPtr, or a HandleRef
  • Not be static
  • Actually be assigned a value from native code

I'm pretty sure that this third bullet is probably the difference between your various structures. The analysis engine (based on a quick dotPeek perusal) will only trigger the warning if it actually finds an instance of your IntPtr being assigned from native code. I haven't yet found exactly what it considers an "assignment from native code" but whatever that is, my best guess is only one of you various struct types is triggering that part of the rule.

Note that this is based on reading the actual code of the current implementation of the Code Analysis engine as ships with VS2010. It is absolutely not a documented behavior of the rule, but likely a specific optimization to reduce false positives. You should not assume that code which currently "passes" this rule (e.g. because it's never assigned from native code) will always do so, as MS is free to change the implementation details at any time.

As mentioned in my comment, suppressing the message is a perfectly legitimate response in this case; this is not one of the FxCop rules that should never be suppressed. The rule is very context-specific and only applies if you're allocating a native resource of your own. If you are only passing the struct back and forth between C# and unmanaged code, then you can most likely just suppress the warning and move on.

like image 94
Michael Edenfield Avatar answered Jan 17 '23 17:01

Michael Edenfield


It's quite clearly spelled out in the article you linked:

This rule assumes that IntPtr, UIntPtr, and HandleRef fields store pointers to unmanaged resources. Types that allocate unmanaged resources should implement IDisposable to let callers to release those resources on demand and shorten the lifetimes of the objects that hold the resources.

So just the plain appearance of IntPtr in the struct is enough to trigger the warning. After you verified that you really didn't forget to release the native resource, apply the [SuppressMessage] attribute on the struct to not have to look at this message again.

like image 34
Hans Passant Avatar answered Jan 17 '23 16:01

Hans Passant