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

DomCR / ACadSharp / 26441668970

26 May 2026 08:37AM UTC coverage: 76.998% (+0.02%) from 76.976%
26441668970

push

github

DomCR
pipeline fix

8611 of 12141 branches covered (70.92%)

Branch coverage included in aggregate %.

31117 of 39455 relevant lines covered (78.87%)

157402.86 hits per line

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

64.94
/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
                        {
1,550,155✔
26
                                if (this._assignedCode.HasValue)
1,550,155!
27
                                        return this._assignedCode.Value;
1,550,155✔
28

29
                                if (this.DxfCodes.Length == 1)
×
30
                                        return this.DxfCodes.First();
×
31
                                else
32
                                        return (int)DxfCode.Invalid;
×
33
                        }
1,550,155✔
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(); } }
840,850✔
43

44
                /// <summary>
45
                /// Gets the type of reference associated with the attribute.
46
                /// </summary>
47
                public DxfReferenceType ReferenceType { get { return this._attributeData.ReferenceType; } }
29,518,824✔
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
                {
59
                        get { return this._storedValue; }
225✔
60
                        set
61
                        {
646✔
62
                                this._storedValue = value;
646✔
63

64
                                return;
646✔
65

66
                                //Does it need a validation??
67
                                switch (this.GroupCode)
68
                                {
69
                                        case GroupCodeValueType.None:
70
                                                this._storedValue = value;
71
                                                break;
72
                                        case GroupCodeValueType.String when value is string:
73
                                        case GroupCodeValueType.ExtendedDataString when value is string:
74
                                        case GroupCodeValueType.Comment when value is string:
75
                                                this._storedValue = value as string;
76
                                                break;
77
                                        case GroupCodeValueType.Point3D when value is IVector v:
78
                                                this._storedValue = v;
79
                                                break;
80
                                        case GroupCodeValueType.Double when value is double:
81
                                        case GroupCodeValueType.ExtendedDataDouble when value is double:
82
                                                this._storedValue = value as double?;
83
                                                break;
84
                                        case GroupCodeValueType.Byte when value is byte b:
85
                                                this._storedValue = b;
86
                                                break;
87
                                        case GroupCodeValueType.Int16 when value is bool bo:
88
                                                this._storedValue = bo ? 1 : 0;
89
                                                break;
90
                                        case GroupCodeValueType.Int16 when value is short:
91
                                        case GroupCodeValueType.ExtendedDataInt16 when value is short:
92
                                                this._storedValue = value as short?;
93
                                                break;
94
                                        case GroupCodeValueType.Int32 when value is int:
95
                                        case GroupCodeValueType.ExtendedDataInt32 when value is int:
96
                                                this._storedValue = value as int?;
97
                                                break;
98
                                        case GroupCodeValueType.Int64 when value is long l:
99
                                                this._storedValue = l;
100
                                                break;
101
                                        case GroupCodeValueType.Handle when value is ulong:
102
                                        case GroupCodeValueType.ObjectId when value is ulong:
103
                                        case GroupCodeValueType.ExtendedDataHandle when value is ulong:
104
                                                if (value is ulong handle)
105
                                                {
106
                                                        this._storedValue = handle;
107
                                                }
108
                                                break;
109
                                        case GroupCodeValueType.Bool when value is bool b:
110
                                                this._storedValue = b;
111
                                                break;
112
                                        case GroupCodeValueType.Chunk when value is byte[]:
113
                                        case GroupCodeValueType.ExtendedDataChunk when value is byte[]:
114
                                                this._storedValue = value as byte[];
115
                                                break;
116
                                        default:
117
                                                throw new ArgumentException($"Invalid type {value.GetType()} for group code {this.GroupCode}");
118
                                }
119
                        }
646✔
120
                }
121

122
                /// <summary>
123
                /// Gets the group code value associated with this instance.
124
                /// </summary>
125
                public GroupCodeValueType GroupCode
126
                {
127
                        get
128
                        {
15✔
129
                                var code = this.DxfCodes[0];
15✔
130
                                return GroupCodeValue.TransformValue(code);
15✔
131
                        }
15✔
132
                }
133

134
                protected int? _assignedCode;
135

136
                protected T _attributeData;
137

138
                protected PropertyInfo _property;
139

140
                protected object _storedValue = null;
2,088,669✔
141

142
                protected DxfPropertyBase(PropertyInfo property)
2,088,669✔
143
                {
2,088,669✔
144
                        this._attributeData = property.GetCustomAttribute<T>();
2,088,669✔
145

146
                        if (this._attributeData == null)
2,088,668✔
147
                                throw new ArgumentException($"The property does not implement the {nameof(DxfCodeValueAttribute)}", nameof(property));
1✔
148

149
                        this._property = property;
2,088,667✔
150
                }
2,088,667✔
151

152
                /// <summary>
153
                /// Set the value for the property using the AssignedCode
154
                /// </summary>
155
                /// <typeparam name="TCadObject"></typeparam>
156
                /// <param name="obj"></param>
157
                /// <param name="value"></param>
158
                /// <exception cref="InvalidOperationException"></exception>
159
                public void SetValue<TCadObject>(TCadObject obj, object value)
160
                        where TCadObject : CadObject
161
                {
24✔
162
                        if (this.AssignedCode == (int)DxfCode.Invalid)
24!
163
                                throw new InvalidOperationException("This property has multiple dxf values assigned or doesn't have a default value assigned");
×
164

165
                        this.SetValue(this.AssignedCode, obj, value);
24✔
166
                }
24✔
167

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

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

192
                                this._property.SetValue(obj, vector);
2✔
193
                        }
2✔
194
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(XYZ)))
22✔
195
                        {
3✔
196
                                XYZ vector = (XYZ)this._property.GetValue(obj);
3✔
197

198
                                int index = (code / 10) % 10 - 1;
3✔
199
                                vector[index] = Convert.ToDouble(value);
3✔
200

201
                                this._property.SetValue(obj, vector);
3✔
202
                        }
3✔
203
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
19!
204
                        {
×
205
                                switch (code)
×
206
                                {
207
                                        case 62:
208
                                                this._property.SetValue(obj, new Color((short)value));
×
209
                                                break;
×
210
                                        case 420:
211
                                                byte[] b = LittleEndianConverter.Instance.GetBytes((int)value);
×
212
                                                // true color
213
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
×
214
                                                break;
×
215
                                }
216
                        }
×
217
                        else if (_property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
19!
218
                        {
×
219
                                PaperMargin margin = (PaperMargin)_property.GetValue(obj);
×
220

221
                                switch (code)
×
222
                                {
223
                                        //40        Size, in millimeters, of unprintable margin on left side of paper
224
                                        case 40:
225
                                                margin = new PaperMargin((double)value, margin.Bottom, margin.Right, margin.Top);
×
226
                                                break;
×
227
                                        //41        Size, in millimeters, of unprintable margin on bottom of paper
228
                                        case 41:
229
                                                margin = new PaperMargin(margin.Left, (double)value, margin.Right, margin.Top);
×
230
                                                break;
×
231
                                        //42        Size, in millimeters, of unprintable margin on right side of paper
232
                                        case 42:
233
                                                margin = new PaperMargin(margin.Left, margin.Bottom, (double)value, margin.Top);
×
234
                                                break;
×
235
                                        //43        Size, in millimeters, of unprintable margin on top of paper
236
                                        case 43:
237
                                                margin = new PaperMargin(margin.Left, margin.Bottom, margin.Right, (double)value);
×
238
                                                break;
×
239
                                }
240

241
                                this._property.SetValue(obj, margin);
×
242
                        }
×
243
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
19!
244
                        {
×
245
                                this._property.SetValue(obj, Transparency.FromAlphaValue((int)value));
×
246
                        }
×
247
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(bool)))
19!
248
                        {
×
249
                                this._property.SetValue(obj, Convert.ToBoolean(value));
×
250
                        }
×
251
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(char)))
19!
252
                        {
×
253
                                this._property.SetValue(obj, Convert.ToChar(value));
×
254
                        }
×
255
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(byte)))
19!
256
                        {
×
257
                                this._property.SetValue(obj, Convert.ToByte(value));
×
258
                        }
×
259
                        else if (this._property.PropertyType.IsEnum)
19✔
260
                        {
11✔
261
                                this._property.SetValue(obj, Enum.ToObject(this._property.PropertyType, value));
11✔
262
                        }
11✔
263
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(ushort)))
8!
264
                        {
×
265
                                this._property.SetValue(obj, Convert.ToUInt16(value));
×
266
                        }
×
267
                        else
268
                        {
8✔
269
                                this._property.SetValue(obj, value);
8✔
270
                        }
8✔
271
                }
24✔
272

273
                internal void SetValue(int code, object obj, object value)
274
                {
2,313,549✔
275
                        if (this._property.PropertyType.IsEquivalentTo(typeof(XY)))
2,313,549✔
276
                        {
18,914✔
277
                                XY vector = (XY)this._property.GetValue(obj);
18,914✔
278

279
                                int index = (code / 10) % 10 - 1;
18,914✔
280
                                vector[index] = Convert.ToDouble(value);
18,914✔
281

282
                                this._property.SetValue(obj, vector);
18,914✔
283
                        }
18,914✔
284
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(XYZ)))
2,294,635✔
285
                        {
1,097,178✔
286
                                XYZ vector = (XYZ)this._property.GetValue(obj);
1,097,178✔
287

288
                                int index = (code / 10) % 10 - 1;
1,097,178✔
289
                                vector[index] = Convert.ToDouble(value);
1,097,178✔
290

291
                                this._property.SetValue(obj, vector);
1,097,178✔
292
                        }
1,097,178✔
293
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
1,197,457✔
294
                        {
142,921✔
295
                                switch (code)
142,921✔
296
                                {
297
                                        case 62:
298
                                                this._property.SetValue(obj, new Color((short)value));
109,219✔
299
                                                break;
109,219✔
300
                                        case 90:
301
                                                byte[] b = LittleEndianConverter.Instance.GetBytes((int)(value));
4,872✔
302
                                                // true color
303
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
4,872✔
304
                                                break;
4,872✔
305
                                        case 420:
306
                                                b = LittleEndianConverter.Instance.GetBytes((int)value);
7,090✔
307
                                                // true color
308
                                                this._property.SetValue(obj, new Color(b[2], b[1], b[0]));
7,090✔
309
                                                break;
7,090✔
310
                                }
311
                        }
142,921✔
312
                        else if (_property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
1,054,536✔
313
                        {
3,420✔
314
                                PaperMargin margin = (PaperMargin)_property.GetValue(obj);
3,420✔
315

316
                                switch (code)
3,420✔
317
                                {
318
                                        //40        Size, in millimeters, of unprintable margin on left side of paper
319
                                        case 40:
320
                                                margin = new PaperMargin((double)value, margin.Bottom, margin.Right, margin.Top);
855✔
321
                                                break;
855✔
322
                                        //41        Size, in millimeters, of unprintable margin on bottom of paper
323
                                        case 41:
324
                                                margin = new PaperMargin(margin.Left, (double)value, margin.Right, margin.Top);
855✔
325
                                                break;
855✔
326
                                        //42        Size, in millimeters, of unprintable margin on right side of paper
327
                                        case 42:
328
                                                margin = new PaperMargin(margin.Left, margin.Bottom, (double)value, margin.Top);
855✔
329
                                                break;
855✔
330
                                        //43        Size, in millimeters, of unprintable margin on top of paper
331
                                        case 43:
332
                                                margin = new PaperMargin(margin.Left, margin.Bottom, margin.Right, (double)value);
855✔
333
                                                break;
855✔
334
                                }
335

336
                                this._property.SetValue(obj, margin);
3,420✔
337
                        }
3,420✔
338
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
1,051,116✔
339
                        {
26,020✔
340
                                this._property.SetValue(obj, Transparency.FromAlphaValue((int)value));
26,020✔
341
                        }
26,020✔
342
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(bool)))
1,025,096✔
343
                        {
94,848✔
344
                                this._property.SetValue(obj, Convert.ToBoolean(value));
94,848✔
345
                        }
94,848✔
346
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(char)))
930,248✔
347
                        {
1,995✔
348
                                this._property.SetValue(obj, Convert.ToChar(value));
1,995✔
349
                        }
1,995✔
350
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(byte)))
928,253✔
351
                        {
5,114✔
352
                                this._property.SetValue(obj, Convert.ToByte(value));
5,114✔
353
                        }
5,114✔
354
                        else if (this._property.PropertyType.IsEnum)
923,139✔
355
                        {
382,421✔
356
                                this._property.SetValue(obj, Enum.ToObject(this._property.PropertyType, value));
382,421✔
357
                        }
382,421✔
358
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(ushort)))
540,718!
359
                        {
×
360
                                this._property.SetValue(obj, Convert.ToUInt16(value));
×
361
                        }
×
362
                        else
363
                        {
540,718✔
364
                                this._property.SetValue(obj, value);
540,718✔
365
                        }
540,718✔
366
                }
2,313,549✔
367

368
                protected int getCounterValue<TCadObject>(TCadObject obj)
369
                {
×
370
                        if (!this._property.PropertyType.HasInterface<IEnumerable>())
×
371
                                throw new ArgumentException();
×
372

373
                        IEnumerable collection = (IEnumerable)this._property.GetValue(obj);
×
374
                        if (collection == null)
×
375
                                return 0;
×
376

377
                        int counter = 0;
×
378
                        foreach (var item in collection)
×
379
                        {
×
380
                                counter++;
×
381
                        }
×
382

383
                        return counter;
×
384
                }
×
385

386
                protected ulong? getHandledValue<TCadObject>(TCadObject obj)
387
                {
192✔
388
                        if (!this._property.PropertyType.HasInterface<IHandledCadObject>())
192!
389
                                throw new ArgumentException($"Property {this._property.Name} for type : {obj.GetType().FullName} does not implement IHandledCadObject");
×
390

391
                        IHandledCadObject handled = (IHandledCadObject)this._property.GetValue(obj);
192✔
392

393
                        return handled?.Handle;
192✔
394
                }
192✔
395

396
                protected string getNamedValue<TCadObject>(TCadObject obj)
397
                {
×
398
                        if (!this._property.PropertyType.HasInterface<INamedCadObject>())
×
399
                                throw new ArgumentException($"Property {this._property.Name} for type : {obj.GetType().FullName} does not implement INamedCadObject");
×
400

401
                        INamedCadObject handled = (INamedCadObject)this._property.GetValue(obj);
×
402

403
                        return handled?.Name;
×
404
                }
×
405

406
                public object GetRawValue(CadObject obj)
407
                {
1,816✔
408
                        return this.getRawValue(this.AssignedCode, obj);
1,816✔
409
                }
1,816✔
410

411
                protected object getRawValue<TCadObject>(int code, TCadObject obj)
412
                {
20,416✔
413
                        GroupCodeValueType groupCode = GroupCodeValue.TransformValue(code);
20,416✔
414

415
                        switch (groupCode)
20,416✔
416
                        {
417
                                case GroupCodeValueType.Handle:
418
                                case GroupCodeValueType.ObjectId:
419
                                case GroupCodeValueType.ExtendedDataHandle:
420
                                        return this.getHandledValue<TCadObject>(obj);
192✔
421
                        }
422

423
                        if (this._property.PropertyType.HasInterface<IVector>())
20,224✔
424
                        {
1,395✔
425
                                IVector vector = (IVector)this._property.GetValue(obj);
1,395✔
426

427
                                int index = (code / 10) % 10 - 1;
1,395✔
428
                                return vector[index];
1,395✔
429
                        }
430
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(DateTime)))
18,829✔
431
                        {
1,860✔
432
                                return CadUtils.ToJulianCalendar((DateTime)this._property.GetValue(obj));
1,860✔
433
                        }
434
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(TimeSpan)))
16,969✔
435
                        {
465✔
436
                                return ((TimeSpan)this._property.GetValue(obj)).TotalDays;
465✔
437
                        }
438
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Color)))
16,504✔
439
                        {
72✔
440
                                //TODO: Implement color getter
441
                                Color color = (Color)this._property.GetValue(obj);
72✔
442

443
                                switch (code)
72!
444
                                {
445
                                        case 62:
446
                                        case 70:
447
                                        case 176:
448
                                        case 177:
449
                                        case 178:
450
                                                return color.Index;
72✔
451
                                        case 420:
452
                                                // true color
453
                                                return color.TrueColor;
×
454
                                        case 430:
455
                                                // dictionary color
456
                                                break;
×
457
                                }
458

459
                                return null;
×
460
                        }
461
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(PaperMargin)))
16,432!
462
                        {
×
463
                                switch (code)
×
464
                                {
465
                                        case 40:
466
                                                return ((PaperMargin)this._property.GetValue(obj)).Left;
×
467
                                        case 41:
468
                                                return ((PaperMargin)this._property.GetValue(obj)).Bottom;
×
469
                                        case 42:
470
                                                return ((PaperMargin)this._property.GetValue(obj)).Right;
×
471
                                        case 43:
472
                                                return ((PaperMargin)this._property.GetValue(obj)).Top;
×
473
                                        default:
474
                                                throw new Exception();
×
475
                                }
476
                        }
477
                        else if (this._property.PropertyType.IsEquivalentTo(typeof(Transparency)))
16,432!
478
                        {
×
479
                                //TODO: Implement transparency getter
480
                                //return this._property.GetValue(obj);
481
                                return null;
×
482
                        }
483
                        else
484
                        {
16,432✔
485
                                return this._property.GetValue(obj);
16,432✔
486
                        }
487
                }
20,416✔
488
        }
489
}
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