System.Linq.Dynamic.Core icon indicating copy to clipboard operation
System.Linq.Dynamic.Core copied to clipboard

Documentation: limitations of type usage to accessible types is incorrectly stated

Open zspitz opened this issue 5 years ago • 2 comments

From the documentation:

Category Expression Description
Primary x.m Instance field or property access. Any public field or property can be accessed.
Primary x.m(...) Instance method invocation. The method must be public and must be declared in an accessible type.
... ... ...
Primary T.m Static field or static property access. Any public field or property can be accessed.
Primary T.m(...) Static method invocation. The method must be public and must be declared in an accessible type.

This is incorrect:

  • All instance methods are allowed, not just the instance methods on an accessible type
    public class Foo {
        public string TestMethod() => "";
    }
    // runs successfully
    var results = (new List<Foo>()).AsQueryable().Where("TestMethod() = \"\"").ToArray();
    
  • Like static methods, static fields or properties are only allowed on accessible types; not any public field or property can be accessed
  public static class Bar {
      public readonly static string EmptyString = "";
  }
  // fails: System.Linq.Dynamic.Core.Exceptions.ParseException: 'No property or field 'Bar' exists in type 'String''
  var results = (new List<string>()).AsQueryable().Where("it = Bar.EmptyString").ToArray();

zspitz avatar Oct 18 '20 09:10 zspitz

@JonathanMagnan

Apparently, things are not so simple. Instance methods are allowed only if either the instance type is an accessible type, or the return type is an accessible type. So this code:

public class Person {
    public void Notify() { }
    public bool Notify1() => true;
    public Person Notify2() => null;
}

var selectors = new[] {
    "Notify()",
    "Notify1()",
    "Notify2()"
};
foreach (var selector in selectors) {
    Console.WriteLine(selector);
    try {
        var prm = Parameter(typeof(Person));
        var parser = new ExpressionParser(new[] { prm }, selector, new object[] { }, ParsingConfig.Default);
        var expr = parser.Parse(null);
        Console.WriteLine("(success)");
    } catch (Exception ex) {
        Console.WriteLine(ex.Message);
    }
    Console.WriteLine();
}

outputs this:

Notify()
Methods on type 'Person' are not accessible

Notify1()
(success)

Notify2()
Methods on type 'Person' are not accessible

because Notify's return type is void, while Notify2's return type is Person. Only Notify1's return type is an accessible type -- bool (Source).

(NB. I see that there's also an explicit exclusion for void-returning methods, even if the instance type is accessible.)

Is this behavior by design?

zspitz avatar Oct 28 '20 17:10 zspitz

Also, I would add that unlike instance methods, indexers can return an inaccessible type.

zspitz avatar Oct 28 '20 20:10 zspitz