Souci avec implémentation de IDbConnection et nullablité

Souci avec implémentation de IDbConnection et nullablité - C#/.NET managed - Programmation

Marsh Posté le 24-01-2025 à 10:16:19    

Bonjour,
 
Pour les besoins d'un projet, j'ai dû écrire une petite lib permettant d'utiliser un IDataReader basé sur un chemin XPath dans un fichier XML plutôt que le résultat d'une requête SQL dans une base de données.
 
Outre les aspects métaphysiques permettant de déterminer le bien du mal d'une telle pratique, je me heurte à des messages d'avertissement lors de la compilation que je n'arrive pas à résoudre dans mon implémentation de IDbConnection.
 
Je suis avec .NET 9.0 et C# 13.0 avec l'option "Nullable = enable".

Code :
  1. <Project Sdk="Microsoft.NET.Sdk">
  2.  <PropertyGroup>
  3.    <TargetFramework>net9.0</TargetFramework>
  4.    <ImplicitUsings>enable</ImplicitUsings>
  5.    <Nullable>enable</Nullable>
  6.  </PropertyGroup>
  7. </Project>


 
Voici le code :

Code :
  1. using System.Data;
  2. using System.Xml;
  3.  
  4. namespace AZToolBox.Xml
  5. {
  6.    public class XmlConnection : IDbConnection
  7.    {
  8.        private bool open = false;
  9.        internal XmlReader? Reader;
  10.  
  11.        private bool disposedValue;
  12.  
  13.        public XmlConnection() : this(null)
  14.        {
  15.        }
  16.  
  17.        public XmlConnection(string? connectionString)
  18.        {
  19.            if (connectionString is null)
  20.            {
  21.                ConnectionString = string.Empty;
  22.            }
  23.            else
  24.            {
  25.                ConnectionString = connectionString;
  26.            }
  27.        }
  28.  
  29.        public string ConnectionString { get; set; }
  30.  
  31.        public int ConnectionTimeout => throw new NotImplementedException();
  32.  
  33.        public string Database => throw new NotImplementedException();
  34.  
  35.        public ConnectionState State
  36.        {
  37.            get
  38.            {
  39.                if (open)
  40.                {
  41.                    return ConnectionState.Open;
  42.                }
  43.                else
  44.                {
  45.                    return ConnectionState.Closed;
  46.                }
  47.            }
  48.        }
  49.  
  50.        public IDbTransaction BeginTransaction()
  51.        {
  52.            throw new NotImplementedException();
  53.        }
  54.  
  55.        public IDbTransaction BeginTransaction(IsolationLevel il)
  56.        {
  57.            throw new NotImplementedException();
  58.        }
  59.  
  60.        public void ChangeDatabase(string databaseName)
  61.        {
  62.            throw new NotImplementedException();
  63.        }
  64.  
  65.        public void Close()
  66.        {
  67.            if (Reader is not null)
  68.            {
  69.                Reader.Close();
  70.                Reader.Dispose();
  71.                Reader = null;
  72.            }
  73.            open = false;
  74.        }
  75.  
  76.        public IDbCommand CreateCommand()
  77.        {
  78.            return new XmlCommand(this);
  79.        }
  80.  
  81.        public void Open()
  82.        {
  83.            Reader = XmlReader.Create(ConnectionString);
  84.            open = true;
  85.        }
  86.  
  87.        protected virtual void Dispose(bool disposing)
  88.        {
  89.            if (!disposedValue)
  90.            {
  91.                if (disposing)
  92.                {
  93.                    // TODO: supprimer l'état managé (objets managés)
  94.                    Close();
  95.                }
  96.  
  97.                // TODO: libérer les ressources non managées (objets non managés) et substituer le finaliseur
  98.                // TODO: affecter aux grands champs une valeur null
  99.                disposedValue = true;
  100.            }
  101.        }
  102.  
  103.        // // TODO: substituer le finaliseur uniquement si 'Dispose(bool disposing)' a du code pour libérer les ressources non managées
  104.        // ~XmlConnection()
  105.        // {
  106.        //     // Ne changez pas ce code. Placez le code de nettoyage dans la méthode 'Dispose(bool disposing)'
  107.        //     Dispose(disposing: false);
  108.        // }
  109.  
  110.        public void Dispose()
  111.        {
  112.            // Ne changez pas ce code. Placez le code de nettoyage dans la méthode 'Dispose(bool disposing)'
  113.            Dispose(disposing: true);
  114.            GC.SuppressFinalize(this);
  115.        }
  116.    }
  117. }


 
Et les avertissements :

Citation :


Ligne 29, sur le set de ConnectionString, j'ai un CS8767 :
La nullabilité des types référence dans le type du paramètre 'value' de 'void XmlConnection.ConnectionString.set' ne correspond pas au membre implémenté implicitement 'void IDbConnection.ConnectionString.set' (probablement en raison des attributs de nullabilité).


 
Si je transforme ConnectionString en string? j'ai cette fois un autre numéro d'erreur, inverse, sur les get.
 
J'ai tenté de passer par un attribut privé et des tests explicites de nullabilité, à la fois avec une propriété string et string?, mais ça ne change rien.
 
J'ai l'impression que ça vient du fait que IDbConnection a été compilé en mode "string peut être null" alors que mon projet, lui, l'interdit.
 
J'ai les mêmes soucis sur mes implémentations de IDbCommand.CommandText et IDataReader.
 
Ça n'empêche pas de compiler, mais un code avec des warnings j'aime pas ça.
Une idée pour résoudre ?

Reply

Marsh Posté le 24-01-2025 à 10:16:19   

Reply

Marsh Posté le 24-01-2025 à 14:51:51    

Bon, ben c'était tout simple...

Code :
  1. [AllowNull]
  2. public string ConnectionString { get; set; }

Reply

Marsh Posté le 25-01-2025 à 10:09:00    

Pas si simple que ça je trouve, avec l'introduction de #nullable, y a plein de trucs qui sont apparus (required, null forgive operator, les attributs d'analyse statiques que tu viens de découvrir...).  
Sur du code "moderne" ça reste très simple (vu qu'on peut s'en passer ou les utiliser juste à bon escient), mais dès qu'on mixe du legacy (comme là cette interface) ça devient parfois bien tordu.
 
 
"Outre les aspects métaphysiques permettant de déterminer le bien du mal d'une telle pratique" : ok alors on n'en parlera pas :d


---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 27-01-2025 à 19:10:12    

TotalRecall a écrit :

"Outre les aspects métaphysiques permettant de déterminer le bien du mal d'une telle pratique" : ok alors on n'en parlera pas :d


N'empêche, c'est vachement pratique :D

 
Code :
  1. using (XmlConnection cnx = new("test.xml" ))
  2.            {
  3.                cnx.Open();
  4.                XmlCommand cmd = cnx.CreateCommand();
  5.                cmd.CommandText = "select @firstname as Nom, @lastname as Prenom, @birth as Age from /personnes/personne[substring(@birth, 1, 4) > '2024' or (substring(@birth, 1, 4) = '2024' and substring(@birth, 6, 2) > '03')]";
  6.                XmlDataReader xmlDataReader = cmd.ExecuteReader();
  7.  
  8.                DataTable dtSchema = xmlDataReader.GetSchemaTable()!;
  9.                
  10.                DataTable dataTable = new();
  11.                dataTable.Load(xmlDataReader);
  12.  
  13.                dataGridView1.DataSource = dataTable;
  14.                
  15.                cnx.Close();
  16.            }
 

Pour le contexte, réel, c'est pour une application en ligne de commande qui permet de transformer le résultat d'une requête SQL en CSV.
Vu que je passais déjà par des interfaces pour pouvoir taper dans SQL Server, Oracle, MySQL ou je ne sais quoi en natif, oledb ou odbc, je me suis dis qu'au point où j'en étais, autant permettre de faire la même chose à partir d'un fichier XML.
L'avantage c'est qu'une fois IDbConnection, IDbCommand et IDataReader implémentés j'ai pas eu à changer une ligne de code du programme existant ;)


Message édité par Arjuna le 27-01-2025 à 19:11:01
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed