17

I have a problem with passing an anonymous object as an argument in a method. I want to pass the object like in JavaScript. Example:

function Test(obj) {
    return obj.txt;
}
console.log(Test({ txt: "test"}));

But in C#, it throws many exceptions:

class Test
{
    public static string TestMethod(IEnumerable<dynamic> obj)
    {
        return obj.txt;
    }
}
Console.WriteLine(Test.TestMethod(new { txt = "test" }));

Exceptions:

  1. Argument 1: cannot convert from 'AnonymousType#1' to 'System.Collections.Generic.IEnumerable'
  2. The best overloaded method match for 'ConsoleApplication1.Test.TestMethod(System.Collections.Generic.IEnumerable)' has some invalid arguments
  3. 'System.Collections.Generic.IEnumerable' does not contain a definition for 'txt' and no extension method 'txt' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found (are you missing a using directive or an assembly reference?)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user1091156
  • 239
  • 1
  • 2
  • 8

3 Answers3

34

It looks like you want:

class Test
{
    public static string TestMethod(dynamic obj)
    {
        return obj.txt;
    }
}

You're using it as if it's a single value, not a sequence. Do you really want a sequence?

Servy
  • 202,030
  • 26
  • 332
  • 449
13

This should do it...

class Program
{
    static void Main(string[] args)
    {
        var test = new { Text = "test", Slab = "slab"};
        Console.WriteLine(test.Text); //outputs test
        Console.WriteLine(TestMethod(test));  //outputs test
    }

    static string TestMethod(dynamic obj)
    {
        return obj.Text;
    }
}
GrayFox374
  • 1,742
  • 9
  • 13
3

This works fine :)

public class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine(Test.TestMethod(new[] {new {txt = "test"}}));
        Console.ReadLine();
    }
}

public class Test
{
    public static string TestMethod(IEnumerable<dynamic> obj)
    {
        return obj.Select(o => o.txt).FirstOrDefault();
    }
}
Rookian
  • 19,841
  • 28
  • 110
  • 180
  • Thank you, works perfect. I'm just shocked at how many options there are for writing a thing :) – user1091156 May 30 '12 at 19:05
  • If you're just going to grab the first item why take an enumerable in the first place? – Servy May 30 '12 at 19:38
  • @Servy Just an observer here stumbling upon this now but it's just a test; it doesn't matter. IMO it's good to test with IEnumerable because it proves out the syntax convention of using new[] { new {..}} which is how anonymous objects are often passed in sets. In fact this is what I needed to see; I'm using it as a 'params' param. – Jon Davis May 31 '12 at 19:27
  • @stimpy77 I see two solutions to this problem. 1. Change the parameter to be a single value, because clearly (as in, he's indicated this after asking the question) that's what the OP really wants. 2. Take an `IEnumerable` of items and perform the operation on *all* of them. If he simply returned a sequence of *all* of the strings, or did something with *all* of the strings, then it would be appropriate. My guess is you're not just `.FirstOrDefault`-ing your `params` list, are you? – Servy May 31 '12 at 19:32
  • I agree that if you're going to just take the first value you should never have an IEnumerable param in the first place. Since the OP currently shows an IEnumerable input and a singular output, I was just suggesting that at least the test, however ridiculous, proves out that if you did have it as such you can still get data out. The contention is that Javascript hashtables (as in the OP first sample) are enumerable. But the equivalence in C# is the multiple members per object; a dynamic object has members and they may be enumerable. Thus you're right, IEnumerable isn't right; dynamic suffices. – Jon Davis May 31 '12 at 21:28
  • my implementation of TestMethod was just an example that as you pointed out makes not much sense. I did not know what user1091156 really wants do. He could also need some logic in the TestMethod. – Rookian Jun 01 '12 at 08:23