Extend "lightweight dynamic" (#3555) with method invocations, etc.
var r = obj.$Property;
var r = obj.TryGetProperty("Property");
var r = obj.$Method()
var r = obj.TryInvokeMember("Method", Array.Empty<Argument>());
var r = obj.$Method(arg: 1)
var r = obj.TryInvokeMember("Method", new[] { new Argument(name: "arg", value: 1) });
var r = obj.$[1];
var r = obj.TryGetIndexer(...);
TryInvoke
, TryGetIndexer
, etc could be convention based and not depend on a base class or interface.
This would be a lightweight compile-time alternative to System.Dynamic.DynamicObject
.
Note: first use case could prefer an indexer as proposed in #3555 to be more useful with existing types.
If you just want a dynamic argument list:
var r = obj.Method$(arg: 1)
var r = obj.Method(new [] { new Argument(name: "arg", value: 1) })
Alternatively you could use #6949, e.g obj.M({ "arg": value });
.
@alrz
How would you access a name/property that has a space or other invalid characters in it?
Maybe it would make sense to do something like this:
var r = obj.$["Some Property"];
Or even this:
var r = obj.$"Some Property";
That will get generated into the following:
var r = obj.TryGetProperty("Some Property");
How would you access a name/property that has a space or other invalid characters in it?
You cannot. The point of #3555 is to use identifiers as a shortcut for dictionary keys. I think in JS you will also need to use indexer syntax for non-identifier names.
@alrz Makes sense, thanks.
I'm not convinced that dynamic is as slow as everyone seems to assume it is. There are plenty of cases where it is more than sufficient.
@aluanhaddad Well it's more generalized approach, need no DLR and it's a compile-time feature so there's less plumbing involved, I _guess_ that this is where the _lightweight_ notion of it comes from, also, I think that both are useful in different circumstances.
@alrz You said we will need to use an indexer do you mean we will have to do something like this obj.$["Some Property"];
?
How is failure to invoke handled? What are the return types?
@eyalsk No, it would resolve to obj.TryGetIndexer(" ... ")
. I updated OP to include this.
@bondsbw Unlike DynamicObject, there would be no runtime failure as in "bind failure", because this is translated at the compile-time, however, methods are free to return null (or throw) in case of not being able to handle the input. I'm thinking that #3555 should also implicitly cast to the target type, if any. so string r = s.$X;
would translate to string r = s.TryGetProperty("X") as string
or something like that.
@eyalsk thank you. That clarifies things.
@alrz how would that work? If I write something like
C#
var r = obj.$Missing();
shouldn't that throw a RuntimeBinderException (or a lightweight dynamic equivalent)?
@aluanhaddad That makes sense only in a dynamic context. Missing
is just a string passed to TryGetProperty
(or an indexer as proposed in #3555), so it can't really be "missing" unless that method doesn't know how to handle it, in which case it is up to its implementation.
Most helpful comment
I'm not convinced that dynamic is as slow as everyone seems to assume it is. There are plenty of cases where it is more than sufficient.