I have an implementation of DynamicDictionary where all of the entries in the dictionary are of a known type:
public class FooClass
{
public void SomeMethod()
{
}
}
dynamic dictionary = new DynamicDictionary<FooClass>();
dictionary.foo = new FooClass();
dictionary.foo2 = new FooClass();
dictionary.foo3 = DateTime.Now; <--throws exception since DateTime is not FooClass
What I'd like is to be able to have Visual Studio Intellisense work when referencing a method of one of the dictionary entries:
dictionary.foo.SomeMethod() <--would like SomeMethod to pop up in intellisense
The only way I've found to do this is:
((FooClass)dictionary.foo).SomeMethod()
Can anyone recommend a more elegant syntax? I'm comfortable writing a custom implementation of DynamicDictionary with IDynamicMetaObjectProvider.
UPDATE:
Some have asked why dynamics and what my specific problem is. I have a system that lets me do something like this:
UI.Map<Foo>().Action<int, object>(x => x.SomeMethodWithParameters).Validate((parameters) =>
{
//do some method validation on the parameters
return true; //return true for now
}).WithMessage("The parameters are not valid");
In this case the method SomeMethodWithParameters has the signature
public void SomeMethodWithParameters(int index, object target)
{
}
What I have right now for registering validation for individual parameters looks like this:
UI.Map<Foo>().Action<int, object>(x => x.SomeMethodWithParameters).GetParameter("index").Validate((val) =>
{
return true; //valid
}).WithMessage("index is not valid");
What I'd like it to be is:
UI.Map<Foo>().Action<int, object(x => x.SomeMethodWithParameters).index.Validate((val) =>
{
return true;
}).WithMessage("index is not valid");
This works using dynamics, but you lose intellisense after the reference to index - which is fine for now. The question is is there a clever syntactical way (other than the ones metioned above) to get Visual Studio to recognize the type somehow. Sounds so far like the answer is "no".
It seems to me that if there was a generic version of IDynamicMetaObjectProvider,
IDynamicMetaObjectProvider<T>
this could be made to work. But there isn't, hence the question.
In order to get intellisense, you're going to have to cast something to a value that is not
dynamic
at some point.If you find yourself doing this a lot, you can use helper methods to ease the pain somewhat:But that isn't much of an improvement over what you've got already. The only other way to get intellisense would be to cast the value back to a non-dynamic type or avoid
dynamic
in the first place.If you want to use Intellisense, it's usually best to avoid using
dynamic
in the first place.Your example makes it seem likely that you have specific expectations about the structure of your
dynamic
object. Consider whether there's a way to create a static class structure that would fulfill your needs.Update
In response to your update: If you don't want to drastically change your syntax, I'd suggest using an indexer so that your syntax can look like this:
Here's my reasoning:
dynamic
approach, there's nothing to indicate that "index" is not a known value from the compiler's perspective.If you're willing to change things around quite a bit, you may want to investigate the way
Moq
plays with expressions in their syntax, particularly theIt.IsAny<T>()
method. It seems like you might be able to do something more along these lines:Unlike your current solution:
Another syntax that's probably slightly easier to accomplish (since it wouldn't require parsing expression trees) might be:
This doesn't give you the advantages listed above, but it still gives you type safety (and therefore intellisense). Pick your poison.
As has already been said (in the question and StriplingWarrior answer) the C# 4
dynamic
type does not provide intellisense support. This answer is provided merely to provide an explanation why (based on my understanding).dynamic
to the C# compiler is nothing more thanobject
which has only limited knowledge at compile-time which members it supports. The difference is, at run-time,dynamic
attempts to resolve members called against its instances against the type for which the instance it represents knows (providing a form of late binding).Consider the following:
In this snippet,
v
represents both an instance ofInt32
(as seen in the first section of code) and an instance ofString
in the latter. The use of the+=
operator actually differs between the two different calls to it because the types involved are inferred at run-time (meaning the compiler doesn't understand or infer usage of the types at compile-time).Now consider a slight variation:
In this example,
v
could potentially be either anInt32
or aString
depending on the time at which the code is run. An extreme example, I know, though it clearly illustrates the problem.Considering a single
dynamic
variable could potentially represent any number of types at run-time, it would be nearly impossible for the compiler or IDE to make assumptions about the types it represents prior to it's execution, so Design- or Compile-time resolution of adynamic
variable's potential members is unreasonable (if not impossible).Aside from Explict Cast,
or Safe Cast,
the only other way to switch back to static invocation (which will allow intellisense to work) is to do Implicit Cast:
Declared casting is your only option, can't use helper methods because they will be dynamically invoked giving you the same problem.
Update:
Not sure if this is more elegant but doesn't involve casting a bunch and gets intellisense outside of the lambda: