Skip to content

Commit 95b2fba

Browse files
author
Dennis Doomen
authored
Allow selecting static properties or fields (#17)
1 parent ab15ff2 commit 95b2fba

File tree

3 files changed

+65
-30
lines changed

3 files changed

+65
-30
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var properties = typeof(SuperClass).GetProperties(
3131
MemberKind.Public | MemberKind.ExplicitlyImplemented | MemberKind.DefaultInterfaceProperties);
3232
```
3333

34-
You can take any of the options `Public`, `Internal`, `ExplictlyImplemented` and `DefaultInterfaceProperties`.
34+
You can take any of the options `Public`, `Internal`, `Static`, `ExplictlyImplemented` and `DefaultInterfaceProperties`.
3535

3636
If you need the fields, use `GetFields` (which obviously cannot be explicitly implemented, nor be part of interfaces), and if you need the members, use `GetMembers`. You can also request individual members by name, like `GetProperty("Name", MemberKind.Public)` or `GetField("Name", MemberKind.Internal)`.
3737

src/Reflectify/Reflectify.cs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,8 @@ internal enum MemberKind
535535
Public = 1,
536536
Internal = 2,
537537
ExplicitlyImplemented = 4,
538-
DefaultInterfaceProperties = 8
538+
DefaultInterfaceProperties = 8,
539+
Static = 16
539540
}
540541

541542
internal static class MemberKindExtensions
@@ -564,37 +565,38 @@ public static BindingFlags ToBindingFlags(this MemberKind kind)
564565
internal sealed class Reflector
565566
{
566567
private readonly HashSet<string> collectedPropertyNames = new();
567-
private readonly HashSet<string> collectedFields = new();
568-
private readonly List<FieldInfo> fields = new();
569-
private List<PropertyInfo> properties = new();
568+
private readonly HashSet<string> collectedFieldNames = new();
569+
private readonly List<FieldInfo> selectedFields = new();
570+
private List<PropertyInfo> selectedProperties = new();
570571

571572
public Reflector(Type typeToReflect, MemberKind kind)
572573
{
573574
LoadProperties(typeToReflect, kind);
574575
LoadFields(typeToReflect, kind);
575576

576-
Members = properties.Concat<MemberInfo>(fields).ToArray();
577+
Members = selectedProperties.Concat<MemberInfo>(selectedFields).ToArray();
577578
}
578579

579580
private void LoadProperties(Type typeToReflect, MemberKind kind)
580581
{
581582
while (typeToReflect != null && typeToReflect != typeof(object))
582583
{
583-
var allProperties = typeToReflect.GetProperties(
584-
BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public |
585-
BindingFlags.NonPublic);
584+
BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic;
585+
flags |= kind.HasFlag(MemberKind.Static) ? BindingFlags.Static : BindingFlags.Instance;
586+
587+
var allProperties = typeToReflect.GetProperties(flags);
586588

587589
AddNormalProperties(kind, allProperties);
588590

589591
AddExplicitlyImplementedProperties(kind, allProperties);
590592

591-
AddInterfaceProperties(typeToReflect, kind);
593+
AddInterfaceProperties(typeToReflect, kind, flags);
592594

593595
// Move to the base type
594596
typeToReflect = typeToReflect.BaseType;
595597
}
596598

597-
properties = properties.Where(x => !x.IsIndexer()).ToList();
599+
selectedProperties = selectedProperties.Where(x => !x.IsIndexer()).ToList();
598600
}
599601

600602
private void AddNormalProperties(MemberKind kind, PropertyInfo[] allProperties)
@@ -607,7 +609,7 @@ private void AddNormalProperties(MemberKind kind, PropertyInfo[] allProperties)
607609
if (!collectedPropertyNames.Contains(property.Name) && !property.IsExplicitlyImplemented() &&
608610
HasVisibility(kind, property))
609611
{
610-
properties.Add(property);
612+
selectedProperties.Add(property);
611613
collectedPropertyNames.Add(property.Name);
612614
}
613615
}
@@ -633,29 +635,28 @@ private void AddExplicitlyImplementedProperties(MemberKind kind, PropertyInfo[]
633635

634636
if (!collectedPropertyNames.Contains(name))
635637
{
636-
properties.Add(p);
638+
selectedProperties.Add(p);
637639
collectedPropertyNames.Add(name);
638640
}
639641
}
640642
}
641643
}
642644
}
643645

644-
private void AddInterfaceProperties(Type typeToReflect, MemberKind kind)
646+
private void AddInterfaceProperties(Type typeToReflect, MemberKind kind, BindingFlags flags)
645647
{
646648
if (kind.HasFlag(MemberKind.DefaultInterfaceProperties) || typeToReflect.IsInterface)
647649
{
648-
// Add explicitly implemented interface properties (not included above)
649650
var interfaces = typeToReflect.GetInterfaces();
650651

651652
foreach (var iface in interfaces)
652653
{
653-
foreach (var prop in iface.GetProperties())
654+
foreach (var prop in iface.GetProperties(flags))
654655
{
655656
if (!collectedPropertyNames.Contains(prop.Name) &&
656657
(!prop.GetMethod.IsAbstract || typeToReflect.IsInterface))
657658
{
658-
properties.Add(prop);
659+
selectedProperties.Add(prop);
659660
collectedPropertyNames.Add(prop.Name);
660661
}
661662
}
@@ -667,15 +668,17 @@ private void LoadFields(Type typeToReflect, MemberKind kind)
667668
{
668669
while (typeToReflect != null && typeToReflect != typeof(object))
669670
{
670-
var files = typeToReflect.GetFields(
671-
BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic);
671+
BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic;
672+
flags |= kind.HasFlag(MemberKind.Static) ? BindingFlags.Static : BindingFlags.Instance;
673+
674+
var files = typeToReflect.GetFields(flags);
672675

673676
foreach (var field in files)
674677
{
675-
if (!collectedFields.Contains(field.Name) && HasVisibility(kind, field))
678+
if (!collectedFieldNames.Contains(field.Name) && HasVisibility(kind, field))
676679
{
677-
fields.Add(field);
678-
collectedFields.Add(field.Name);
680+
selectedFields.Add(field);
681+
collectedFieldNames.Add(field.Name);
679682
}
680683
}
681684

@@ -692,7 +695,7 @@ private static bool HasVisibility(MemberKind kind, FieldInfo field)
692695

693696
public MemberInfo[] Members { get; }
694697

695-
public PropertyInfo[] Properties => properties.ToArray();
698+
public PropertyInfo[] Properties => selectedProperties.ToArray();
696699

697-
public FieldInfo[] Fields => fields.ToArray();
700+
public FieldInfo[] Fields => selectedFields.ToArray();
698701
}

tests/Reflectify.Specs/TypeMemberExtensionsSpecs.cs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class TypeMemberExtensionsSpecs
1111
public class GetPropertiesAndFields
1212
{
1313
[Fact]
14-
public void Can_get_all_public_explicit_and_default_interface_properties()
14+
public void Can_get_all_public_explicit_and_default_instance_interface_properties()
1515
{
1616
// Act
1717
var properties = typeof(SuperClass).GetProperties(
@@ -23,7 +23,6 @@ public void Can_get_all_public_explicit_and_default_interface_properties()
2323
new { Name = "NormalProperty", PropertyType = typeof(string) },
2424
new { Name = "NewProperty", PropertyType = typeof(int) },
2525
new { Name = "InterfaceProperty", PropertyType = typeof(string) },
26-
new { Name = "StaticProperty", PropertyType = typeof(bool) },
2726
new
2827
{
2928
Name =
@@ -36,6 +35,19 @@ public void Can_get_all_public_explicit_and_default_interface_properties()
3635
});
3736
}
3837

38+
[Fact]
39+
public void Can_get_all_public_static_properties()
40+
{
41+
// Act
42+
var properties = typeof(SuperClass).GetProperties(
43+
MemberKind.Public | MemberKind.Static);
44+
45+
// Assert
46+
properties.Should().BeEquivalentTo([
47+
new { Name = "StaticProperty", PropertyType = typeof(bool) }
48+
]);
49+
}
50+
3951
[Fact]
4052
public void Can_get_all_properties_from_an_interface()
4153
{
@@ -64,7 +76,6 @@ public void Can_get_normal_public_properties()
6476
{
6577
new { Name = "NormalProperty", PropertyType = typeof(string) },
6678
new { Name = "NewProperty", PropertyType = typeof(int) },
67-
new { Name = "StaticProperty", PropertyType = typeof(bool) },
6879
new { Name = "InterfaceProperty", PropertyType = typeof(string) }
6980
});
7081
}
@@ -217,7 +228,6 @@ public void Can_find_all_members()
217228
new { Name = "NormalProperty" },
218229
new { Name = "NewProperty" },
219230
new { Name = "InterfaceProperty" },
220-
new { Name = "StaticProperty" },
221231
new { Name = "NormalField" },
222232
]);
223233
}
@@ -394,7 +404,7 @@ public void Can_find_an_internal_indexer_if_you_ask_for_ot()
394404
public class FindField
395405
{
396406
[Fact]
397-
public void Can_find_a_public_field()
407+
public void Can_find_a_public_instance_field()
398408
{
399409
// Act
400410
var field = typeof(SuperClass).FindField("NormalField", MemberKind.Public);
@@ -409,12 +419,34 @@ public void Can_find_a_public_field()
409419
public void Cannot_find_a_field_if_it_does_not_exist()
410420
{
411421
// Act
412-
var field = typeof(SuperClass).FindField("NonExistingProperty", MemberKind.Public);
422+
var field = typeof(SuperClass).FindField("NonExistingField", MemberKind.Public);
413423

414424
// Assert
415425
field.Should().BeNull();
416426
}
417427

428+
[Fact]
429+
public void Cannot_find_a_static_field_if_you_dont_ask_for_it()
430+
{
431+
// Act
432+
var field = typeof(SuperClass).FindField("StaticField", MemberKind.Public);
433+
434+
// Assert
435+
field.Should().BeNull();
436+
}
437+
438+
[Fact]
439+
public void Can_find_a_static_field_if_you_ask_for_it()
440+
{
441+
// Act
442+
var field = typeof(SuperClass).FindField("StaticField", MemberKind.Public | MemberKind.Static);
443+
444+
// Assert
445+
field.Should().NotBeNull();
446+
field.Name.Should().Be("StaticField");
447+
field.FieldType.Should().Be<bool>();
448+
}
449+
418450
[Theory]
419451
[InlineData("")]
420452
[InlineData(null)]

0 commit comments

Comments
 (0)