Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Bug in CodeDom GenerateEvent: MemberAttributes.New wird nicht berücksichtigt
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

Themenstarter:

Bug in CodeDom GenerateEvent: MemberAttributes.New wird nicht berücksichtigt

beantworten | zitieren | melden

Hallo Miteinander

Ich habe einen Bug gefunden im CodeDom. Kann das bitte jemand verifizieren.

Auf dem CodeDom generiere ich aufgrund von Metadaten gewisse Klassen. Dabei kann es vorkommen, dass eine Klasse vererbt wird. Die vererbte Klasse erbt natürlich auch die Events der BasisKlasse. Allerdings kann es sein, dass die vererbende Klasse denselben Event erweitern muss (es wird dabei ein EventArgs verwendet welches vom EventArgs der BasisKlasse abgeleitet ist).

Idealerweise blendet der Event der neuen Klasse den Event der BasisKlasse nur aus.

Folgendes Sample soll aufzeigen was ich mache.

Klasse A ist die Basisklasse mit einem Event vom Type EventHandler (EventArgs).

Klasse B leitet von A ab und will den Event ausblenden und stellt dafür einen Event (mit demselben Namen) vom Type CancelEventHandler bereit (dessen CancelEventArgs leitet ja von EventArgs ab).


Effektiv sind es natürlich eigene EventArgs-Klassen (aber das würde das Sample nur unnötig kompliziert machen).



using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.CodeDom;
using System.CodeDom.Compiler;

namespace BugInCodeComGenerateEvent
{
    class Program
    {
        static void Main(string[] args)
        {
            string strGeneratedCode = null;
            System.CodeDom.CodeCompileUnit ccu = new System.CodeDom.CodeCompileUnit();
            System.CodeDom.Compiler.CodeDomProvider provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("CSharp");

            CodeNamespace ns = new CodeNamespace("Bug");
            ccu.Namespaces.Add(ns);

            //Create a new Class  A
            CodeTypeDeclaration ctdA = new CodeTypeDeclaration("A");
            ns.Types.Add(ctdA);
            
            //Create a new Event TestEvent in A
            CodeMemberEvent cmeATestEvent = new CodeMemberEvent();
            cmeATestEvent.Name = "TestEvent";
            cmeATestEvent.Type = new CodeTypeReference(typeof(EventHandler));
            cmeATestEvent.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            ctdA.Members.Add(cmeATestEvent);

            //Create a new Class B (Inherits from A)
            CodeTypeDeclaration ctdB = new CodeTypeDeclaration("B");
            ctdB.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            ctdB.BaseTypes.Add("A");
            ns.Types.Add(ctdB);

            //Create a new Event TestEvent in B
            CodeMemberEvent cmeBTestEvent = new CodeMemberEvent();
            cmeBTestEvent.Name = "TestEvent";
            cmeBTestEvent.Type = new CodeTypeReference(typeof(System.ComponentModel.CancelEventHandler));
            cmeBTestEvent.Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.New;
            cmeBTestEvent.Comments.Add(new CodeCommentStatement("public event EventHandler TestEvent; is wrong (new-Attribute is missing)"));
            cmeBTestEvent.Comments.Add(new CodeCommentStatement("public new event EventHandler TestEvent; would be correct"));
            ctdB.Members.Add(cmeBTestEvent);

            /*
             * Have a look at: Class: Microsoft.CSharp.CSharpCodeGenerator
             * 
             * Compare Methods: GenerateMethod with GenerateEvent
             * 
             * GenerateMethod calls:
             * 
             * 			this.OutputMemberAccessModifier(e.Attributes);    (public / internal protected ....)
			            this.OutputVTableModifier(e.Attributes);          (new )
			            this.OutputMemberScopeModifier(e.Attributes);     (abstract / virtual ....)
             * 
             * GenerateEvent only calls:
             * 
             * this.OutputMemberAccessModifier(e.Attributes);    (public / internal protected ....)
             * 
             * --- Calls to OutputVTableModifier and OutputMemberScopeModifier are missing
             */

            using (MemoryStream ms = new MemoryStream())
            {
                IndentedTextWriter tw = new IndentedTextWriter(new StreamWriter(ms));
                // Generate source code using the code generator.
                provider.GenerateCodeFromCompileUnit(ccu, tw, new CodeGeneratorOptions());
                // Close the output file.
                tw.Close();
                strGeneratedCode = System.Text.Encoding.UTF8.GetString(ms.GetBuffer());
            }
            System.Diagnostics.Debug.WriteLine(strGeneratedCode);
            Console.WriteLine(strGeneratedCode);
        }
    }
}



myCSharp hat doch gute Kontakte zu MS... falls sich der Fehler bestätigt... wäre doch toll wenn das Forum den Fehler zu MS rüberschieben könnte.


Edit: Hier noch der Output:


namespace Bug {
    
    
    public class A {
        
        public event System.EventHandler TestEvent;
    }
    
    public class B : A {
        
        // public event EventHandler TestEvent; is wrong (new-Attribute is missing)
        // public new event EventHandler TestEvent; would be correct
        public event System.ComponentModel.CancelEventHandler TestEvent;
    }
}

Gruss
Programmierhans
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Programmierhans am .
Attachments
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Programmierhans,

im Grunde ist doch die Frage, warum wird der Event in B trotz der Zeile
Zitat

cmeBTestEvent.Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.New;

nicht als new markiert. Auch dann nicht, wenn man an allen Stellen im Code das MemberAttributes.Final weglässt. Wenn man dagegen testweise CodeMemberEvent durch CodeMemberField ersetzt, wird das new eingefügt. Das spricht schon dafür, dass es sich um einen Bug handelt.

Ich persönlich habe keine Kontakte zu Microsoft. Aber ich denke, du könnten den Fehler auch selber auf http://connect.microsoft.com melden.

Anderseits produziert ein fehlendes new nur eine Warnung:
Fehler
warning CS0108: "B.TestEvent" blendet den vererbten Member "A.TestEvent" aus. Verwenden Sie das new-Schlüsselwort, wenn das Ausblenden vorgesehen war.

Wenn man die Warnung ignoriert, funktioniert alles wie gewünscht.

herbivore
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5.649
Herkunft: Leipzig

beantworten | zitieren | melden

Hi Programmierhans,

ich seh das genauso wie herbivore. Ich verstehe zwar auch nicht, warum du die Events als sealed deklariert hast, aber auch ich hab keinen Weg gefunden, ein new event zu erzeugen. Auch nicht mit statischen Events, während beides für Felder und Methoden funktioniert.

Christian
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

Themenstarter:

beantworten | zitieren | melden

Danke euch beiden...

Gibt es allenfalls ein Attribut [CompilerHaltFresseBeiWarnung(CSxx)] welches ich noch drauf generieren könnte um den Compiler zum Schweigen zu bringen (ich habe keines gefunden)...

Sonst werde ich mit der Warnung leben ... gibt schlimmere Probleme.

Gruss
Programmierhans
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Programmierhans,

es gibt #pragma warning (C#-Referenz). Das scheint man auch per CodeDom generieren zu können, siehe z.B. How to add #pragma warning disable 1591 using CodeDom.

herbivore
private Nachricht | Beiträge des Benutzers
Programmierhans
myCSharp.de - Experte

Avatar #avatar-1651.gif


Dabei seit:
Beiträge: 4.221
Herkunft: Zentralschweiz

Themenstarter:

beantworten | zitieren | melden

Hallo herbivore

Nicht schlecht die Idee... wobei bei einem Event kann ich das Pragma nur als Member des Typen einfügen (es kommt dann einfach immer ganz am Anfang der Klasse)...


ctdB.Members.Add(new CodeSnippetTypeMember("#pragma warning disable 0108"));

Aber so ist die Warnung nun weg.

Danke sehr vielmals

Gruss
Programmierhans
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
private Nachricht | Beiträge des Benutzers