Extension Method and Dynamic Object

Extension method and dynamic object

To expand on Stecya's answer... extension methods aren't supported by dynamic typing in the form of extension methods, i.e. called as if they were instance methods. However, this will work:

dynamic dList = list;
Console.WriteLine(Enumerable.First(dList));

Of course, that may or may not be useful. If you could give more information about why and how you're trying to use dynamic typing, we may be able to help more.

Creating a dynamic extension method in C#?

No. See https://stackoverflow.com/a/5311527/613130

When you use a dynamic object, you can't call an extension method through the "extension method syntax". To make it clear:

int[] arr = new int[5];
int first1 = arr.First(); // extension method syntax, OK
int first2 = Enumerable.First(arr); // plain syntax, OK

Both of these are ok, but with dynamic

dynamic arr = new int[5];
int first1 = arr.First(); // BOOM!
int first2 = Enumerable.First(arr); // plain syntax, OK

This is logical if you know how dynamic objects work. A dynamic variable/field/... is just an object variable/field/... (plus an attribute) that the C# compiler knows that should be treated as dynamic. And what does "treating as dynamic" means? It means that generated code, instead of using directly the variable, uses reflection to search for required methods/properties/... inside the type of the object (so in this case, inside the int[] type). Clearly reflection can't go around all the loaded assemblies to look for extension methods that could be anywhere.

Adding new object property dynamically from extension method

You need to inherit your object from DynamicObject:

public class AObject : DynamicObject
{
public string PropertyA { get; set; }

public int PropertyB { get; set; }

#region Dynamic Part

private readonly Dictionary<string, object> _members = new Dictionary<string, object>();

public override bool TrySetMember(SetMemberBinder binder, object value)
{
this._members[binder.Name] = value;
return true;
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return this._members.TryGetValue(binder.Name, out result) || base.TryGetMember(binder, out result);
}

public override IEnumerable<string> GetDynamicMemberNames()
{
return this._members.Keys;
}

#endregion
}

Your extension method has to be changed to:

public static class AObjectExtensions
{
public static void DoSomething(this AObject a, string value)
{
((dynamic)a).PropertyC = value;
}
}

You have the ability to iterate over all dynamic members using GetDynamicMemberNames() and if AObject provides an indexer or a getter method that accesses this._members you can access to all dynamic values.

EDIT:
There meight be a problem using this solution. I didn't tested it. ((dynamic)a).PropertyA meight be hidden by Try(Get|Set)Member. If so you can change the getter and setter of PropertyA and ProprertyB to access the _members or you can handle this cases in Try(Get|Set)Member. Adding these properties to _member opens up the possibility to iterate over these members too.

How to call an extension method of a dynamic type?

Like this:

dynamic numbers = Enumerable.Range(10, 10);
var firstFive = Enumerable.Take(numbers, 5);

In other words, just call it as a static method instead of as an extension method.

Or if you know an appropriate type argument you could just cast it, which I'd typically do with an extra variable:

dynamic numbers = Enumerable.Range(10, 10);
var sequence = (IEnumerable<int>) numbers;
var firstFive = sequence.Take(5);

... but if you're dealing with dynamic types, you may well not know the sequence element type, in which case the first version lets the "execution time compiler" figure it out, basically.

dynamic keyword with builder pattern hides extension method

This happens because passing a dynamic parameter makes C# compiler treat the return type of the expression, i.e. .SetBody(dynamicString), as dynamic (relevant explanation of method return types with dynamic parameters).

Extension methods work with dynamic objects only as regular methods, not as extension methods (see Eric Lippert's answer for an explanation of this), hence the compile-time error that you see.

Extension functions does not work for dynamic objects

Correct, extension functions do not work for dynamic objects. That is because the dynamic object, when being told to execute ParseLong, has no clue what using directives were in your C# code, so cannot guess what you want to do.

Extension methods are 100% a compiler feature (only); dynamic is primarily a runtime feature (although the compiler has to help it in places).

You could just cast, though, if you know the type:

long x = ((string)x.StartValue).ParseLong();

(which swaps back from dynamic to regular C#, so extension methods work)

Extension methods & dynamic vars

The ToList from Linq expects a compile-time-IEnumerable. By using dynamic you completely hide the compile-time-type and make it impossible for the compiler to infer the right method. So you rely on runtime-binding.

Now an extension-method is just syntactic sugar for a static method:

static class Enumerable
{
public static List<T> ToList(IEnumerable<T> e) { ...}
}

which you would call like this:

Enumerable.ToList(myHashSet);

This is what the compiler does also. It translates all calls to hashSet.ToList() into Enumerable.ToList(hashSet).

This method has nothing to do with your actual class - the hashset - because extension-methods don't modify existing classes. They just define methods that seem like if they were added to the class. Or in other words: at runtime - this is when dynamic is evaluated - there is no such method HashSet.ToList, but Enumerable.ToList.



Related Topics



Leave a reply



Submit