• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DomCR / ACadSharp / 20457200384

23 Dec 2025 09:42AM UTC coverage: 76.854% (-0.3%) from 77.148%
20457200384

Pull #924

github

web-flow
Merge fde81b197 into 886606be2
Pull Request #924: issue 923 - dim style override

7696 of 10903 branches covered (70.59%)

Branch coverage included in aggregate %.

49 of 176 new or added lines in 8 files covered. (27.84%)

123 existing lines in 7 files now uncovered.

28361 of 36013 relevant lines covered (78.75%)

159201.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.53
/src/ACadSharp/DxfPropertyBase.cs
1
using ACadSharp.Attributes;
2
using ACadSharp.Objects;
3
using CSMath;
4
using CSUtilities.Converters;
5
using CSUtilities.Extensions;
6
using System;
7
using System.Collections;
8
using System.Linq;
9
using System.Reflection;
10

11
namespace ACadSharp
12
{
13
        public abstract class DxfPropertyBase<T>
14
                where T : Attribute, ICodeValueAttribute
15
        {
16
                /// <summary>
17
                /// Gets the code currently assigned to this instance.
18
                /// </summary>
19
                /// <remarks>If an explicit assigned code is not set, the value is determined based on the associated DXF
20
                /// codes. If there is exactly one DXF code, that code is returned; otherwise, an invalid code value is
21
                /// returned.</remarks>
22
                public int AssignedCode
23
                {
24
                        get
25
                        {
18✔
26
                                if (this._assignedCode.HasValue)
18!
27
                                        return this._assignedCode.Value;
18✔
28

29
                                if (this.DxfCodes.Length == 1)
×
30
                                        return this.DxfCodes.First();
×
31
                                else
32
                                        return (int)DxfCode.Invalid;
×
33
                        }
18✔
34
                }
35

36
                /// <summary>
37
                /// Gets the collection of DXF group codes associated with the attribute data.
38
                /// </summary>
39
                /// <remarks>DXF group codes identify the type and meaning of each value in the attribute data according to
40
                /// the DXF specification. The order of codes in the array corresponds to the order of values in the attribute
41
                /// data.</remarks>
42
                public int[] DxfCodes { get { return this._attributeData.ValueCodes.Select(c => (int)c).ToArray(); } }
935,218✔
43

44
                /// <summary>
45
                /// Gets the type of reference associated with the attribute.
46
                /// </summary>
47
                public DxfReferenceType ReferenceType { get { return this._attributeData.ReferenceType; } }
33,346,872✔
48

49
                /// <summary>
50
                /// Gets or sets the value associated with the current group code, using the appropriate type based on the group code
51
                /// definition.
52
                /// </summary>
53
                /// <remarks>The type of the value must match the expected type for the group code as determined by the DXF
54
                /// specification. Assigning a value of an incorrect type will result in an exception. Supported types include string,
55
                /// numeric types, boolean, byte arrays, and custom handled objects, depending on the group code. When setting this
56
                /// property, the value is automatically converted or validated according to the group code's requirements.</remarks>
57
                public object StoredValue
58
                {
NEW
59
                        get { return this._storedValue; }
×
60
                        set
NEW
61
                        {
×
NEW
62
                                var code = this.DxfCodes[0];
×
NEW
63
                                var groupCode = GroupCodeValue.TransformValue(code);
×
NEW
64
                                switch (groupCode)
×
65
                                {
66
                                        case GroupCodeValueType.None:
NEW
67
                                                this._storedValue = value;
×
NEW
68
                                                break;
×
NEW
69
                                        case GroupCodeValueType.String when value is string:
×
NEW
70
                                        case GroupCodeValueType.ExtendedDataString when value is string:
×
NEW
71
                                        case GroupCodeValueType.Comment when value is string:
×
NEW
72
                                                this._storedValue = value as string;
×
NEW
73
                                                break;
×
NEW
74
                                        case GroupCodeValueType.Point3D when value is IVector v:
×
NEW
75
                                                this._storedValue = v;
×
NEW
76
                                                break;
×
NEW
77
                                        case GroupCodeValueType.Double when value is double:
×
NEW
78
                                        case GroupCodeValueType.ExtendedDataDouble when value is double:
×
NEW
79
                                                this._storedValue = value as double?;
×
NEW
80
                                                break;
×
NEW
81
                                        case GroupCodeValueType.Byte when value is byte b:
×
NEW
82
                                                this._storedValue = b;
×
NEW
83
                                                break;
×
NEW
84
                                        case GroupCodeValueType.Int16 when value is short:
×
NEW
85
                                        case GroupCodeValueType.ExtendedDataInt16 when value is short:
×
NEW
86
                                                this._storedValue = value as short?;
×
NEW
87
                                                break;
×
NEW
88
                                        case GroupCodeValueType.Int32 when value is int:
×
NEW
89
                                        case GroupCodeValueType.ExtendedDataInt32 when value is int:
×
NEW
90
                                                this._storedValue = value as int?;
×
NEW
91
                                                break;
×
NEW
92
                                        case GroupCodeValueType.Int64 when value is long l:
×
NEW
93
                                                this._storedValue = l;
×
NEW
94
                                                break;
×
NEW
95
                                        case GroupCodeValueType.Handle when value is IHandledCadObject:
×
NEW
96
                                        case GroupCodeValueType.ObjectId when value is IHandledCadObject:
×
NEW
97
                                        case GroupCodeValueType.ExtendedDataHandle when value is IHandledCadObject:
×
NEW
98
                                                if (value is IHandledCadObject handled)
×
NEW
99
                                                {
×
NEW
100
                                                        this._storedValue = handled.Handle;
×
NEW
101
                                                }
×
NEW
102
                                                break;
×
NEW
103
                                        case GroupCodeValueType.Bool when value is bool b:
×
NEW
104
                                                this._storedValue = b;
×
NEW
105
                                                break;
×
NEW
106
                                        case GroupCodeValueType.Chunk when value is byte[]:
×
NEW
107
                                        case GroupCodeValueType.ExtendedDataChunk when value is byte[]:
×
NEW
108
                                                this._storedValue = value as byte[];
×
NEW
109
                                                break;
×
110
                                        default:
NEW
111
                                                throw new ArgumentException($"Invalid type {value.GetType()} for group code {groupCode}");
×
112
                                }
NEW
113
                        }
×
114
                }
115

116
                protected int? _assignedCode;
117

118
                protected T _attributeData;
119

120
                protected PropertyInfo _property;
121

122
                protected object _storedValue = null;
559,751✔
123

124
                protected DxfPropertyBase(PropertyInfo property)
559,751✔
125
                {
559,751✔
126
                        this._attributeData = property.GetCustomAttribute<T>();
559,751✔
127

128
                        if (this._attributeData == null)
559,750✔
129
                                throw new ArgumentException($"The property does not implement the {nameof(DxfCodeValueAttribute)}", nameof(property));
1✔
130

131
                        this._property = property;
559,749✔
132
                }
559,749✔
133

134
                /// <summary>
135
                /// Set the value for the property using the AssignedCode
136
                /// </summary>
137
                /// <typeparam name="TCadObject"></typeparam>
138
                /// <param name="obj"></param>
139
                /// <param name="value"></param>
140
                /// <exception cref="InvalidOperationException"></exception>
141
                public void SetValue<TCadObject>(TCadObject obj, object value)
142
                        where TCadObject : CadObject
143
                {
9✔
144
                        if (this.AssignedCode == (int)DxfCode.Invalid)
9!
UNCOV
145
                                throw new InvalidOperationException("This property has multiple dxf values assigned or doesn't have a default value assigned");
×
146

147
                        this.SetValue(this.AssignedCode, obj, value);
9✔
148
                }
9✔
149

150
                /// <summary>
151
                /// Sets the value of a specified property on a CAD object, converting the value as needed based on the property's
152
                /// type.
153
                /// </summary>
154
                /// <remarks>This method supports setting values for various property types, including vectors (<see
155
                /// cref="XY"/> and <see cref="XYZ"/>), colors (<see cref="Color"/>), margins (<see cref="PaperMargin"/>),
156
                /// transparency (<see cref="Transparency"/>), and other primitive or enum types. The behavior of the method depends
157
                /// on the property's type and the provided <paramref name="code"/>.</remarks>
158
                /// <typeparam name="TCadObject">The type of the CAD object on which the property value is being set. Must derive from <see cref="CadObject"/>.</typeparam>
159
                /// <param name="code">A code that determines how the value should be interpreted or applied. The interpretation of this code depends on
160
                /// the property's type.</param>
161
                /// <param name="obj">The CAD object whose property value is being set. Cannot be <see langword="null"/>.</param>
162
                /// <param name="value">The value to set for the property. The value will be converted to the appropriate type based on the property's
163
                /// type.</param>
164
                public void SetValue<TCadObject>(int code, TCadObject obj, object value)
165
                        where TCadObject : CadObject
166
                {
9✔
167
                        if (this._property.PropertyType.IsEquivalentTo(typeof(XY)))
9✔
168
                        {
2✔
169
                                XY vector = (XY)this._property.GetValue(obj);
2✔
170

171
                                int index = (code / 10) % 10 - 1;
2✔
172
                                vector[index] = Convert.ToDouble(value);
2✔
173

174
                                this._property.SetValue(obj, vector);
2✔
175
                        }
2✔
176
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(XYZ)))
7✔
177
                        {
3✔
178
                                XYZ vector = (XYZ)this._property.GetValue(obj);
3✔
179

180
                                int index = (code / 10) % 10 - 1;
3✔
181
                                vector[index] = Convert.ToDouble(value);
3✔
182

183
                                this._property.SetValue(obj, vector);
3✔
184
                        }
3✔
185
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
4!
UNCOV
186
                        {
×
UNCOV
187
                                switch (code)
×
188
                                {
189
                                        case 62:
UNCOV
190
                                                this._property.SetValue(obj, new Color((short)value));
×
UNCOV
191
                                                break;
×
192
                                        case 420:
UNCOV
193
                                                byte[] b = LittleEndianConverter.Instance.GetBytes((int)value);
×
194
                                                // true color
UNCOV
195
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
×
196
                                                break;
×
197
                                }
UNCOV
198
                        }
×
199
                        else if (_property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
4!
200
                        {
×
201
                                PaperMargin margin = (PaperMargin)_property.GetValue(obj);
×
202

203
                                switch (code)
×
204
                                {
205
                                        //40        Size, in millimeters, of unprintable margin on left side of paper
206
                                        case 40:
UNCOV
207
                                                margin = new PaperMargin((double)value, margin.Bottom, margin.Right, margin.Top);
×
208
                                                break;
×
209
                                        //41        Size, in millimeters, of unprintable margin on bottom of paper
210
                                        case 41:
211
                                                margin = new PaperMargin(margin.Left, (double)value, margin.Right, margin.Top);
×
UNCOV
212
                                                break;
×
213
                                        //42        Size, in millimeters, of unprintable margin on right side of paper
214
                                        case 42:
UNCOV
215
                                                margin = new PaperMargin(margin.Left, margin.Bottom, (double)value, margin.Top);
×
UNCOV
216
                                                break;
×
217
                                        //43        Size, in millimeters, of unprintable margin on top of paper
218
                                        case 43:
UNCOV
219
                                                margin = new PaperMargin(margin.Left, margin.Bottom, margin.Right, (double)value);
×
UNCOV
220
                                                break;
×
221
                                }
222

UNCOV
223
                                this._property.SetValue(obj, margin);
×
UNCOV
224
                        }
×
225
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
4!
226
                        {
×
UNCOV
227
                                this._property.SetValue(obj, Transparency.FromAlphaValue((int)value));
×
UNCOV
228
                        }
×
229
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(bool)))
4!
230
                        {
×
UNCOV
231
                                this._property.SetValue(obj, Convert.ToBoolean(value));
×
UNCOV
232
                        }
×
233
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(char)))
4!
234
                        {
×
UNCOV
235
                                this._property.SetValue(obj, Convert.ToChar(value));
×
236
                        }
×
237
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(byte)))
4!
238
                        {
×
UNCOV
239
                                this._property.SetValue(obj, Convert.ToByte(value));
×
240
                        }
×
241
                        else if (this._property.PropertyType.IsEnum)
4!
242
                        {
4✔
243
                                this._property.SetValue(obj, Enum.ToObject(this._property.PropertyType, value));
4✔
244
                        }
4✔
245
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(ushort)))
×
246
                        {
×
UNCOV
247
                                this._property.SetValue(obj, Convert.ToUInt16(value));
×
248
                        }
×
249
                        else
250
                        {
×
UNCOV
251
                                this._property.SetValue(obj, value);
×
UNCOV
252
                        }
×
253
                }
9✔
254

255
                internal void SetValue(int code, object obj, object value)
256
                {
2,633,657✔
257
                        if (this._property.PropertyType.IsEquivalentTo(typeof(XY)))
2,633,657✔
258
                        {
20,866✔
259
                                XY vector = (XY)this._property.GetValue(obj);
20,866✔
260

261
                                int index = (code / 10) % 10 - 1;
20,866✔
262
                                vector[index] = Convert.ToDouble(value);
20,866✔
263

264
                                this._property.SetValue(obj, vector);
20,866✔
265
                        }
20,866✔
266
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(XYZ)))
2,612,791✔
267
                        {
1,220,712✔
268
                                XYZ vector = (XYZ)this._property.GetValue(obj);
1,220,712✔
269

270
                                int index = (code / 10) % 10 - 1;
1,220,712✔
271
                                vector[index] = Convert.ToDouble(value);
1,220,712✔
272

273
                                this._property.SetValue(obj, vector);
1,220,712✔
274
                        }
1,220,712✔
275
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
1,392,079✔
276
                        {
173,542✔
277
                                switch (code)
173,542✔
278
                                {
279
                                        case 62:
280
                                                this._property.SetValue(obj, new Color((short)value));
136,004✔
281
                                                break;
136,004✔
282
                                        case 90:
283
                                                byte[] b = LittleEndianConverter.Instance.GetBytes((int)(value));
5,424✔
284
                                                // true color
285
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
5,424✔
286
                                                break;
5,424✔
287
                                        case 420:
288
                                                b = LittleEndianConverter.Instance.GetBytes((int)value);
7,910✔
289
                                                // true color
290
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
7,910✔
291
                                                break;
7,910✔
292
                                }
293
                        }
173,542✔
294
                        else if (_property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
1,218,537✔
295
                        {
3,768✔
296
                                PaperMargin margin = (PaperMargin)_property.GetValue(obj);
3,768✔
297

298
                                switch (code)
3,768✔
299
                                {
300
                                        //40        Size, in millimeters, of unprintable margin on left side of paper
301
                                        case 40:
302
                                                margin = new PaperMargin((double)value, margin.Bottom, margin.Right, margin.Top);
942✔
303
                                                break;
942✔
304
                                        //41        Size, in millimeters, of unprintable margin on bottom of paper
305
                                        case 41:
306
                                                margin = new PaperMargin(margin.Left, (double)value, margin.Right, margin.Top);
942✔
307
                                                break;
942✔
308
                                        //42        Size, in millimeters, of unprintable margin on right side of paper
309
                                        case 42:
310
                                                margin = new PaperMargin(margin.Left, margin.Bottom, (double)value, margin.Top);
942✔
311
                                                break;
942✔
312
                                        //43        Size, in millimeters, of unprintable margin on top of paper
313
                                        case 43:
314
                                                margin = new PaperMargin(margin.Left, margin.Bottom, margin.Right, (double)value);
942✔
315
                                                break;
942✔
316
                                }
317

318
                                this._property.SetValue(obj, margin);
3,768✔
319
                        }
3,768✔
320
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
1,214,769✔
321
                        {
29,080✔
322
                                this._property.SetValue(obj, Transparency.FromAlphaValue((int)value));
29,080✔
323
                        }
29,080✔
324
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(bool)))
1,185,689✔
325
                        {
117,350✔
326
                                this._property.SetValue(obj, Convert.ToBoolean(value));
117,350✔
327
                        }
117,350✔
328
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(char)))
1,068,339✔
329
                        {
2,202✔
330
                                this._property.SetValue(obj, Convert.ToChar(value));
2,202✔
331
                        }
2,202✔
332
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(byte)))
1,066,137✔
333
                        {
5,690✔
334
                                this._property.SetValue(obj, Convert.ToByte(value));
5,690✔
335
                        }
5,690✔
336
                        else if (this._property.PropertyType.IsEnum)
1,060,447✔
337
                        {
436,909✔
338
                                this._property.SetValue(obj, Enum.ToObject(this._property.PropertyType, value));
436,909✔
339
                        }
436,909✔
340
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(ushort)))
623,538!
UNCOV
341
                        {
×
UNCOV
342
                                this._property.SetValue(obj, Convert.ToUInt16(value));
×
UNCOV
343
                        }
×
344
                        else
345
                        {
623,538✔
346
                                this._property.SetValue(obj, value);
623,538✔
347
                        }
623,538✔
348
                }
2,633,657✔
349

350
                protected int getCounterValue<TCadObject>(TCadObject obj)
351
                {
×
352
                        if (!this._property.PropertyType.HasInterface<IEnumerable>())
×
353
                                throw new ArgumentException();
×
354

UNCOV
355
                        IEnumerable collection = (IEnumerable)this._property.GetValue(obj);
×
UNCOV
356
                        if (collection == null)
×
UNCOV
357
                                return 0;
×
358

UNCOV
359
                        int counter = 0;
×
NEW
360
                        foreach (var item in collection)
×
NEW
361
                        {
×
NEW
362
                                counter++;
×
NEW
363
                        }
×
364

NEW
365
                        return counter;
×
NEW
366
                }
×
367

368
                protected ulong? getHandledValue<TCadObject>(TCadObject obj)
NEW
369
                {
×
NEW
370
                        if (!this._property.PropertyType.HasInterface<IHandledCadObject>())
×
NEW
371
                                throw new ArgumentException($"Property {this._property.Name} for type : {obj.GetType().FullName} does not implement IHandledCadObject");
×
372

NEW
373
                        IHandledCadObject handled = (IHandledCadObject)this._property.GetValue(obj);
×
374

NEW
375
                        return handled?.Handle;
×
NEW
376
                }
×
377

378
                protected string getNamedValue<TCadObject>(TCadObject obj)
379
                {
×
380
                        if (!this._property.PropertyType.HasInterface<INamedCadObject>())
×
381
                                throw new ArgumentException($"Property {this._property.Name} for type : {obj.GetType().FullName} does not implement INamedCadObject");
×
382

383
                        INamedCadObject handled = (INamedCadObject)this._property.GetValue(obj);
×
384

385
                        return handled?.Name;
×
386
                }
×
387

388
                protected object getRawValue<TCadObject>(int code, TCadObject obj)
389
                {
13,455✔
390
                        GroupCodeValueType groupCode = GroupCodeValue.TransformValue(code);
13,455✔
391

392
                        switch (groupCode)
13,455!
393
                        {
394
                                case GroupCodeValueType.Handle:
395
                                case GroupCodeValueType.ObjectId:
396
                                case GroupCodeValueType.ExtendedDataHandle:
UNCOV
397
                                        return this.getHandledValue<TCadObject>(obj);
×
398
                        }
399

400
                        if (this._property.PropertyType.HasInterface<IVector>())
13,455✔
401
                        {
1,035✔
402
                                IVector vector = (IVector)this._property.GetValue(obj);
1,035✔
403

404
                                int index = (code / 10) % 10 - 1;
1,035✔
405
                                return vector[index];
1,035✔
406
                        }
407
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(DateTime)))
12,420✔
408
                        {
1,380✔
409
                                return CadUtils.ToJulianCalendar((DateTime)this._property.GetValue(obj));
1,380✔
410
                        }
411
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(TimeSpan)))
11,040✔
412
                        {
345✔
413
                                return ((TimeSpan)this._property.GetValue(obj)).TotalDays;
345✔
414
                        }
415
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
10,695!
UNCOV
416
                        {
×
417
                                //TODO: Implement color getter
UNCOV
418
                                Color color = (Color)this._property.GetValue(obj);
×
419

UNCOV
420
                                switch (code)
×
421
                                {
422
                                        case 62:
423
                                        case 70:
UNCOV
424
                                                return color.Index;
×
425
                                        case 420:
426
                                                // true color
UNCOV
427
                                                return color.TrueColor;
×
428
                                        case 430:
429
                                                // dictionary color
430
                                                break;
×
431
                                }
432

UNCOV
433
                                return null;
×
434
                        }
435
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
10,695!
UNCOV
436
                        {
×
437
                                switch (code)
×
438
                                {
439
                                        case 40:
440
                                                return ((PaperMargin)this._property.GetValue(obj)).Left;
×
441
                                        case 41:
UNCOV
442
                                                return ((PaperMargin)this._property.GetValue(obj)).Bottom;
×
443
                                        case 42:
UNCOV
444
                                                return ((PaperMargin)this._property.GetValue(obj)).Right;
×
445
                                        case 43:
446
                                                return ((PaperMargin)this._property.GetValue(obj)).Top;
×
447
                                        default:
UNCOV
448
                                                throw new Exception();
×
449
                                }
450
                        }
451
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
10,695!
452
                        {
×
453
                                //TODO: Implement transparency getter
454
                                //return this._property.GetValue(obj);
UNCOV
455
                                return null;
×
456
                        }
457
                        else
458
                        {
10,695✔
459
                                return this._property.GetValue(obj);
10,695✔
460
                        }
461
                }
13,455✔
462
        }
463
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc