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

DomCR / ACadSharp / 20459304191

23 Dec 2025 11:18AM UTC coverage: 76.82% (-0.3%) from 77.148%
20459304191

Pull #924

github

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

7697 of 10907 branches covered (70.57%)

Branch coverage included in aggregate %.

8 of 148 new or added lines in 8 files covered. (5.41%)

2 existing lines in 2 files now uncovered.

28370 of 36043 relevant lines covered (78.71%)

159070.31 hits per line

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

42.34
/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
                                switch (this.GroupCode)
×
63
                                {
64
                                        case GroupCodeValueType.None:
NEW
65
                                                this._storedValue = value;
×
NEW
66
                                                break;
×
NEW
67
                                        case GroupCodeValueType.String when value is string:
×
NEW
68
                                        case GroupCodeValueType.ExtendedDataString when value is string:
×
NEW
69
                                        case GroupCodeValueType.Comment when value is string:
×
NEW
70
                                                this._storedValue = value as string;
×
NEW
71
                                                break;
×
NEW
72
                                        case GroupCodeValueType.Point3D when value is IVector v:
×
NEW
73
                                                this._storedValue = v;
×
NEW
74
                                                break;
×
NEW
75
                                        case GroupCodeValueType.Double when value is double:
×
NEW
76
                                        case GroupCodeValueType.ExtendedDataDouble when value is double:
×
NEW
77
                                                this._storedValue = value as double?;
×
NEW
78
                                                break;
×
NEW
79
                                        case GroupCodeValueType.Byte when value is byte b:
×
NEW
80
                                                this._storedValue = b;
×
NEW
81
                                                break;
×
NEW
82
                                        case GroupCodeValueType.Int16 when value is short:
×
NEW
83
                                        case GroupCodeValueType.ExtendedDataInt16 when value is short:
×
NEW
84
                                                this._storedValue = value as short?;
×
NEW
85
                                                break;
×
NEW
86
                                        case GroupCodeValueType.Int32 when value is int:
×
NEW
87
                                        case GroupCodeValueType.ExtendedDataInt32 when value is int:
×
NEW
88
                                                this._storedValue = value as int?;
×
NEW
89
                                                break;
×
NEW
90
                                        case GroupCodeValueType.Int64 when value is long l:
×
NEW
91
                                                this._storedValue = l;
×
NEW
92
                                                break;
×
NEW
93
                                        case GroupCodeValueType.Handle when value is IHandledCadObject:
×
NEW
94
                                        case GroupCodeValueType.ObjectId when value is IHandledCadObject:
×
NEW
95
                                        case GroupCodeValueType.ExtendedDataHandle when value is IHandledCadObject:
×
NEW
96
                                                if (value is IHandledCadObject handled)
×
NEW
97
                                                {
×
NEW
98
                                                        this._storedValue = handled.Handle;
×
NEW
99
                                                }
×
NEW
100
                                                break;
×
NEW
101
                                        case GroupCodeValueType.Bool when value is bool b:
×
NEW
102
                                                this._storedValue = b;
×
NEW
103
                                                break;
×
NEW
104
                                        case GroupCodeValueType.Chunk when value is byte[]:
×
NEW
105
                                        case GroupCodeValueType.ExtendedDataChunk when value is byte[]:
×
NEW
106
                                                this._storedValue = value as byte[];
×
NEW
107
                                                break;
×
108
                                        default:
NEW
109
                                                throw new ArgumentException($"Invalid type {value.GetType()} for group code {this.GroupCode}");
×
110
                                }
NEW
111
                        }
×
112
                }
113

114
                /// <summary>
115
                /// Gets the group code value associated with this instance.
116
                /// </summary>
117
                public GroupCodeValueType GroupCode
118
                {
119
                        get
NEW
120
                        {
×
NEW
121
                                var code = this.DxfCodes[0];
×
NEW
122
                                return GroupCodeValue.TransformValue(code);
×
NEW
123
                        }
×
124
                }
125

126
                protected int? _assignedCode;
127

128
                protected T _attributeData;
129

130
                protected PropertyInfo _property;
131

132
                protected object _storedValue = null;
560,166✔
133

134
                protected DxfPropertyBase(PropertyInfo property)
560,166✔
135
                {
560,166✔
136
                        this._attributeData = property.GetCustomAttribute<T>();
560,166✔
137

138
                        if (this._attributeData == null)
560,165✔
139
                                throw new ArgumentException($"The property does not implement the {nameof(DxfCodeValueAttribute)}", nameof(property));
1✔
140

141
                        this._property = property;
560,164✔
142
                }
560,164✔
143

144
                /// <summary>
145
                /// Set the value for the property using the AssignedCode
146
                /// </summary>
147
                /// <typeparam name="TCadObject"></typeparam>
148
                /// <param name="obj"></param>
149
                /// <param name="value"></param>
150
                /// <exception cref="InvalidOperationException"></exception>
151
                public void SetValue<TCadObject>(TCadObject obj, object value)
152
                        where TCadObject : CadObject
153
                {
9✔
154
                        if (this.AssignedCode == (int)DxfCode.Invalid)
9!
155
                                throw new InvalidOperationException("This property has multiple dxf values assigned or doesn't have a default value assigned");
×
156

157
                        this.SetValue(this.AssignedCode, obj, value);
9✔
158
                }
9✔
159

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

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

184
                                this._property.SetValue(obj, vector);
2✔
185
                        }
2✔
186
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(XYZ)))
7✔
187
                        {
3✔
188
                                XYZ vector = (XYZ)this._property.GetValue(obj);
3✔
189

190
                                int index = (code / 10) % 10 - 1;
3✔
191
                                vector[index] = Convert.ToDouble(value);
3✔
192

193
                                this._property.SetValue(obj, vector);
3✔
194
                        }
3✔
195
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
4!
196
                        {
×
197
                                switch (code)
×
198
                                {
199
                                        case 62:
200
                                                this._property.SetValue(obj, new Color((short)value));
×
201
                                                break;
×
202
                                        case 420:
203
                                                byte[] b = LittleEndianConverter.Instance.GetBytes((int)value);
×
204
                                                // true color
205
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
×
206
                                                break;
×
207
                                }
208
                        }
×
209
                        else if (_property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
4!
210
                        {
×
211
                                PaperMargin margin = (PaperMargin)_property.GetValue(obj);
×
212

213
                                switch (code)
×
214
                                {
215
                                        //40        Size, in millimeters, of unprintable margin on left side of paper
216
                                        case 40:
217
                                                margin = new PaperMargin((double)value, margin.Bottom, margin.Right, margin.Top);
×
218
                                                break;
×
219
                                        //41        Size, in millimeters, of unprintable margin on bottom of paper
220
                                        case 41:
221
                                                margin = new PaperMargin(margin.Left, (double)value, margin.Right, margin.Top);
×
222
                                                break;
×
223
                                        //42        Size, in millimeters, of unprintable margin on right side of paper
224
                                        case 42:
225
                                                margin = new PaperMargin(margin.Left, margin.Bottom, (double)value, margin.Top);
×
226
                                                break;
×
227
                                        //43        Size, in millimeters, of unprintable margin on top of paper
228
                                        case 43:
229
                                                margin = new PaperMargin(margin.Left, margin.Bottom, margin.Right, (double)value);
×
230
                                                break;
×
231
                                }
232

233
                                this._property.SetValue(obj, margin);
×
234
                        }
×
235
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
4!
236
                        {
×
237
                                this._property.SetValue(obj, Transparency.FromAlphaValue((int)value));
×
238
                        }
×
239
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(bool)))
4!
240
                        {
×
241
                                this._property.SetValue(obj, Convert.ToBoolean(value));
×
242
                        }
×
243
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(char)))
4!
244
                        {
×
245
                                this._property.SetValue(obj, Convert.ToChar(value));
×
246
                        }
×
247
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(byte)))
4!
248
                        {
×
249
                                this._property.SetValue(obj, Convert.ToByte(value));
×
250
                        }
×
251
                        else if (this._property.PropertyType.IsEnum)
4!
252
                        {
4✔
253
                                this._property.SetValue(obj, Enum.ToObject(this._property.PropertyType, value));
4✔
254
                        }
4✔
255
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(ushort)))
×
256
                        {
×
257
                                this._property.SetValue(obj, Convert.ToUInt16(value));
×
258
                        }
×
259
                        else
260
                        {
×
261
                                this._property.SetValue(obj, value);
×
262
                        }
×
263
                }
9✔
264

265
                internal void SetValue(int code, object obj, object value)
266
                {
2,633,657✔
267
                        if (this._property.PropertyType.IsEquivalentTo(typeof(XY)))
2,633,657✔
268
                        {
20,866✔
269
                                XY vector = (XY)this._property.GetValue(obj);
20,866✔
270

271
                                int index = (code / 10) % 10 - 1;
20,866✔
272
                                vector[index] = Convert.ToDouble(value);
20,866✔
273

274
                                this._property.SetValue(obj, vector);
20,866✔
275
                        }
20,866✔
276
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(XYZ)))
2,612,791✔
277
                        {
1,220,712✔
278
                                XYZ vector = (XYZ)this._property.GetValue(obj);
1,220,712✔
279

280
                                int index = (code / 10) % 10 - 1;
1,220,712✔
281
                                vector[index] = Convert.ToDouble(value);
1,220,712✔
282

283
                                this._property.SetValue(obj, vector);
1,220,712✔
284
                        }
1,220,712✔
285
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
1,392,079✔
286
                        {
173,542✔
287
                                switch (code)
173,542✔
288
                                {
289
                                        case 62:
290
                                                this._property.SetValue(obj, new Color((short)value));
136,004✔
291
                                                break;
136,004✔
292
                                        case 90:
293
                                                byte[] b = LittleEndianConverter.Instance.GetBytes((int)(value));
5,424✔
294
                                                // true color
295
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
5,424✔
296
                                                break;
5,424✔
297
                                        case 420:
298
                                                b = LittleEndianConverter.Instance.GetBytes((int)value);
7,910✔
299
                                                // true color
300
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
7,910✔
301
                                                break;
7,910✔
302
                                }
303
                        }
173,542✔
304
                        else if (_property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
1,218,537✔
305
                        {
3,768✔
306
                                PaperMargin margin = (PaperMargin)_property.GetValue(obj);
3,768✔
307

308
                                switch (code)
3,768✔
309
                                {
310
                                        //40        Size, in millimeters, of unprintable margin on left side of paper
311
                                        case 40:
312
                                                margin = new PaperMargin((double)value, margin.Bottom, margin.Right, margin.Top);
942✔
313
                                                break;
942✔
314
                                        //41        Size, in millimeters, of unprintable margin on bottom of paper
315
                                        case 41:
316
                                                margin = new PaperMargin(margin.Left, (double)value, margin.Right, margin.Top);
942✔
317
                                                break;
942✔
318
                                        //42        Size, in millimeters, of unprintable margin on right side of paper
319
                                        case 42:
320
                                                margin = new PaperMargin(margin.Left, margin.Bottom, (double)value, margin.Top);
942✔
321
                                                break;
942✔
322
                                        //43        Size, in millimeters, of unprintable margin on top of paper
323
                                        case 43:
324
                                                margin = new PaperMargin(margin.Left, margin.Bottom, margin.Right, (double)value);
942✔
325
                                                break;
942✔
326
                                }
327

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

360
                protected int getCounterValue<TCadObject>(TCadObject obj)
NEW
361
                {
×
NEW
362
                        if (!this._property.PropertyType.HasInterface<IEnumerable>())
×
NEW
363
                                throw new ArgumentException();
×
364

NEW
365
                        IEnumerable collection = (IEnumerable)this._property.GetValue(obj);
×
NEW
366
                        if (collection == null)
×
NEW
367
                                return 0;
×
368

NEW
369
                        int counter = 0;
×
NEW
370
                        foreach (var item in collection)
×
NEW
371
                        {
×
NEW
372
                                counter++;
×
NEW
373
                        }
×
374

NEW
375
                        return counter;
×
NEW
376
                }
×
377

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

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

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

388
                protected string getNamedValue<TCadObject>(TCadObject obj)
389
                {
×
390
                        if (!this._property.PropertyType.HasInterface<INamedCadObject>())
×
391
                                throw new ArgumentException($"Property {this._property.Name} for type : {obj.GetType().FullName} does not implement INamedCadObject");
×
392

393
                        INamedCadObject handled = (INamedCadObject)this._property.GetValue(obj);
×
394

395
                        return handled?.Name;
×
396
                }
×
397

398
                protected object getRawValue<TCadObject>(int code, TCadObject obj)
399
                {
13,455✔
400
                        GroupCodeValueType groupCode = GroupCodeValue.TransformValue(code);
13,455✔
401

402
                        switch (groupCode)
13,455!
403
                        {
404
                                case GroupCodeValueType.Handle:
405
                                case GroupCodeValueType.ObjectId:
406
                                case GroupCodeValueType.ExtendedDataHandle:
407
                                        return this.getHandledValue<TCadObject>(obj);
×
408
                        }
409

410
                        if (this._property.PropertyType.HasInterface<IVector>())
13,455✔
411
                        {
1,035✔
412
                                IVector vector = (IVector)this._property.GetValue(obj);
1,035✔
413

414
                                int index = (code / 10) % 10 - 1;
1,035✔
415
                                return vector[index];
1,035✔
416
                        }
417
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(DateTime)))
12,420✔
418
                        {
1,380✔
419
                                return CadUtils.ToJulianCalendar((DateTime)this._property.GetValue(obj));
1,380✔
420
                        }
421
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(TimeSpan)))
11,040✔
422
                        {
345✔
423
                                return ((TimeSpan)this._property.GetValue(obj)).TotalDays;
345✔
424
                        }
425
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
10,695!
426
                        {
×
427
                                //TODO: Implement color getter
428
                                Color color = (Color)this._property.GetValue(obj);
×
429

430
                                switch (code)
×
431
                                {
432
                                        case 62:
433
                                        case 70:
434
                                                return color.Index;
×
435
                                        case 420:
436
                                                // true color
437
                                                return color.TrueColor;
×
438
                                        case 430:
439
                                                // dictionary color
440
                                                break;
×
441
                                }
442

443
                                return null;
×
444
                        }
445
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
10,695!
446
                        {
×
447
                                switch (code)
×
448
                                {
449
                                        case 40:
450
                                                return ((PaperMargin)this._property.GetValue(obj)).Left;
×
451
                                        case 41:
452
                                                return ((PaperMargin)this._property.GetValue(obj)).Bottom;
×
453
                                        case 42:
454
                                                return ((PaperMargin)this._property.GetValue(obj)).Right;
×
455
                                        case 43:
456
                                                return ((PaperMargin)this._property.GetValue(obj)).Top;
×
457
                                        default:
458
                                                throw new Exception();
×
459
                                }
460
                        }
461
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
10,695!
462
                        {
×
463
                                //TODO: Implement transparency getter
464
                                //return this._property.GetValue(obj);
465
                                return null;
×
466
                        }
467
                        else
468
                        {
10,695✔
469
                                return this._property.GetValue(obj);
10,695✔
470
                        }
471
                }
13,455✔
472
        }
473
}
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