@@ -104,7 +104,7 @@ public static void AddColumn<T>(this DataTable table, string columnName, T defau
104104 {
105105 row [ columnName ] = defaultValue ! ;
106106 }
107- }
107+ }
108108
109109 /// <summary>
110110 /// Merges multiple DataTables with the same schema into one.
@@ -115,30 +115,50 @@ public static void AddColumn<T>(this DataTable table, string columnName, T defau
115115 public static DataTable MergeTables ( IEnumerable < DataTable > tables )
116116 {
117117 if ( tables == null ) throw new ArgumentNullException ( nameof ( tables ) ) ;
118+ var list = tables . Where ( t => t != null ) . ToList ( ) ;
119+ if ( list . Count == 0 ) throw new ArgumentException ( "No tables." ) ;
118120
119- var resultTable = tables . First ( ) . Clone ( ) ;
120- foreach ( var table in tables )
121+ var result = list [ 0 ] . Clone ( ) ;
122+ foreach ( var t in list )
121123 {
122- if ( ! AreSchemasCompatible ( resultTable , table ) )
124+ if ( ! AreSchemasCompatible ( result , t ) )
123125 throw new ArgumentException ( "Tables have incompatible schemas." ) ;
124-
125- foreach ( DataRow row in table . Rows )
126+ foreach ( DataRow r in t . Rows )
126127 {
127- resultTable . ImportRow ( row ) ;
128+ result . ImportRow ( r ) ;
128129 }
129130 }
130- return resultTable ;
131+
132+ return result ;
131133 }
132134
133- private static bool AreSchemasCompatible ( DataTable table1 , DataTable table2 )
135+ /// <summary>
136+ /// Determines whether two <see cref="DataTable"/> instances have compatible schemas
137+ /// for position-based operations (e.g., cloning and row import).
138+ /// </summary>
139+ /// <param name="table1">
140+ /// The first table whose schema is used as the reference (column order matters).
141+ /// </param>
142+ /// <param name="table2">
143+ /// The second table to compare against <paramref name="table1"/>.
144+ /// </param>
145+ /// <returns>
146+ /// <c>true</c> if both tables have the same number of columns and, at each position,
147+ /// the column name matches (case-insensitive) and the <see cref="Type"/> matches;
148+ /// otherwise, <c>false</c>.
149+ /// </returns>
150+ /// <remarks>
151+ /// This check is strictly positional: it does not attempt to realign columns by name.
152+ /// Extended properties, nullability metadata, constraints, and keys are not compared.
153+ /// </remarks>
154+ private static bool AreSchemasCompatible ( DataTable a , DataTable b )
134155 {
135- if ( table1 . Columns . Count != table2 . Columns . Count ) return false ;
136-
137- for ( int i = 0 ; i < table1 . Columns . Count ; i ++ )
156+ if ( a . Columns . Count != b . Columns . Count ) return false ;
157+ for ( int i = 0 ; i < a . Columns . Count ; i ++ )
138158 {
139- if ( table1 . Columns [ i ] . ColumnName != table2 . Columns [ i ] . ColumnName ||
140- table1 . Columns [ i ] . DataType != table2 . Columns [ i ] . DataType )
141- return false ;
159+ var ca = a . Columns [ i ] ; var cb = b . Columns [ i ] ;
160+ if ( ! ca . ColumnName . Equals ( cb . ColumnName , StringComparison . OrdinalIgnoreCase ) ) return false ;
161+ if ( ca . DataType != cb . DataType ) return false ;
142162 }
143163 return true ;
144164 }
0 commit comments