0

When I declare a public event in a sealed C++/CLI class, I get Code Analysis warning CA1047. The warning seems to come from auto-generated protected member functions. How can I fix this warning?

Here's an example. This code

ref class Test sealed {
public:
    event EventHandler^ blah;
};

generates:

warning: CA1047 : Microsoft.Design : Make member 'Test::blah::raise(Object^, EventArgs^)' private, public, or internal

Eric
  • 6,364
  • 1
  • 32
  • 49

1 Answers1

1

I'll document the question better. This code

ref class Test sealed {
public:
    event EventHandler^ blah;
};

generates:

warning: CA1047 : Microsoft.Design : Make member 'Test::blah::raise(Object^, EventArgs^)' private, public, or internal

Yes, when you don't specify the event accessors yourself then the compiler will generate them for you. It auto-generates the add, remove and raise accessors. The latter one looks like this when you look with ildasm.exe:

.method family hidebysig specialname instance void 
        raise_blah(object value0,
                   class [mscorlib]System.EventArgs value1) cil managed
{
    // etc..
}

The family attribute is what causes the code analysis warning. The auto-generated add and remove accessors are of course public. Writing them yourself is a questionable workaround, you really only want to do this if you have a real reason to implement custom accessors. The boilerplate version would look like this:

using namespace System::Runtime::CompilerServices;

ref class Test sealed {
private:
    EventHandler^ foo;
public:
    event EventHandler^ blah {
        [MethodImpl(MethodImplOptions::Synchronized)]
        void add(EventHandler^ d) { foo += d; }
        [MethodImpl(MethodImplOptions::Synchronized)]
        void remove(EventHandler^ d) { foo -= d; }
    private:
        void raise(Object^ sender, EventArgs^ e) { 
            EventHandler^ handler = foo;
            if (handler != nullptr) handler(sender, e);
        };
    }
};

Well, that certainly suppresses the warning. I recommend you use the [SuppressMessage] attribute if that doesn't spin your propeller.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Is the `raise` accessor actually needed here? After all, the backing property can be used directly, or a simple helper function could be used (to provide the race-condition avoidance logic). Or would the compiler automatically generate a `raise` method if none is explicitly given, and still trigger FxCop? – Ben Voigt Dec 02 '10 at 20:13
  • Too bad the automatic code generation isn't smart enough to set an appropriate accessor on raise. – Eric Dec 03 '10 at 12:49