Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions src/CommandLineUtils/Internal/ReflectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -35,25 +36,25 @@ public static SetPropertyDelegate GetPropertySetter(PropertyInfo prop)

public static MethodInfo[] GetPropertyOrMethod(Type type, string name)
{
const BindingFlags binding = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
return type.GetTypeInfo()
.GetMethods(binding)
var members = GetAllMembers(type.GetTypeInfo()).ToList();
return members
.OfType<MethodInfo>()
.Where(m => m.Name == name)
.Concat(type.GetTypeInfo().GetProperties(binding).Where(m => m.Name == name).Select(p => p.GetMethod))
.Concat(members.OfType<PropertyInfo>().Where(m => m.Name == name).Select(p => p.GetMethod))
.Where(m => m.ReturnType == typeof(string) && m.GetParameters().Length == 0)
.ToArray();
}

public static PropertyInfo[] GetProperties(Type type)
{
const BindingFlags binding = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
return type.GetTypeInfo().GetProperties(binding);
return GetAllMembers(type.GetTypeInfo())
.OfType<PropertyInfo>()
.ToArray();
}

public static MemberInfo[] GetMembers(Type type)
{
const BindingFlags binding = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
return type.GetTypeInfo().GetMembers(binding);
return GetAllMembers(type.GetTypeInfo()).ToArray();
}

public static object[] BindParameters(MethodInfo method, CommandLineApplication command, CancellationToken cancellationToken)
Expand Down Expand Up @@ -102,5 +103,21 @@ public static bool IsNullableType(TypeInfo typeInfo, out Type? wrappedType)

return result;
}

static IEnumerable<MemberInfo> GetAllMembers(TypeInfo typeInfo)
{
const BindingFlags binding = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly;

while (typeInfo != null)
{
var members = typeInfo.GetMembers(binding);
foreach (var member in members)
{
yield return member;
}

typeInfo = typeInfo.BaseType?.GetTypeInfo();
}
}
}
}
19 changes: 19 additions & 0 deletions test/CommandLineUtils.Tests/OptionAttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,25 @@ public void BindsToStaticPropertiesWithSetterMethod()
Assert.Equal(2, PrivateSetterProgram.StaticValue);
}

abstract class PrivateBaseType
{
[Option]
int Count { get; }

public int GetCount() => Count;
}

class WithPrivateBaseTypeApplication : PrivateBaseType
{
}

[Fact]
public void BindsToPrivateBaseTypeProperty()
{
var parsed = CommandLineParser.ParseArgs<WithPrivateBaseTypeApplication>("--count", "42");
Assert.Equal(42, parsed.GetCount());
}

[Theory]
[InlineData("Option123", "o", "option123", "OPTION123")]
[InlineData("dWORD", "d", "d-word", "D_WORD")]
Expand Down