2

I can already hear the close vote clicks... lol, oh well.

Ok so I wrote a method that took a Dictionary but then I got this idea to just pass an anonymous type instead so the method calls are less verbose, and then I just convert it to a Dictionary in the method.

However, after this update the compiler is not going to point out to me any calls that are still passing a dictionary since the parameter is just an object.

So I just started wondering if there's a way to enforce the type as anonymous? I actually feel fairly certain the answer is no and if someone just wants to post an answer that simply says "No" (followed by enough characters to be accepted as an answer... and perhaps letting me know how ridiculous my request is while you're at it as well) then I will happily mark that as the answer.

Was just curious enough I had to ask though. Don't hate me for it! :)

BVernon
  • 3,205
  • 5
  • 28
  • 64
  • @cl0ud Yup, I am using object. What I'm saying is that now that it's an object, I need to go back and update the calls that send a Dictionary in to be an anonymous type instead. Normally when you change the method signature the compiler will point out all the broken method calls you haven't updated; but in this case since it now takes an object anything will be considered valid by the compiler. – BVernon Oct 16 '18 at 06:41
  • 1
    No, you can't have a method that takes in an anonymous type - but you can use `object` or `dynamic` as cl0ud wrote. – Zohar Peled Oct 16 '18 at 06:41
  • @BVernon But if you're gonna cast it to a dictionary why change those callers? Just let it be a dictionary – EpicKip Oct 16 '18 at 06:45
  • 2
    Check this: [how-to-test-if-a-type-is-anonymous](https://stackoverflow.com/questions/2483023/how-to-test-if-a-type-is-anonymous) – Fabjan Oct 16 '18 at 06:46
  • @Fabjan why are we testing if the type is anonymous ? – TheGeneral Oct 16 '18 at 06:46
  • 2
    @TheGeneral To enforce type as anonymous it's sufficient to check if object passed to method is of correct type and if not - throw an exception... But for that one would need to know how to check that – Fabjan Oct 16 '18 at 06:47
  • @EpicKip Yeah... I could do that but I figured just for consistency I will make all calls the same. – BVernon Oct 16 '18 at 06:54

3 Answers3

2

No, you can't have a method that takes in an anonymous type - but you can use object or dynamic as cl0ud wrote.

However, the reason on why you would want such a thing is not clear to me. You say to want to make the method call less verbose - but instead of paying the cost of typing in a few more letters and pressing ctrl+space you are subjecting the users of this method to potential runtime exceptions that should have been avoided by throwing compile time exceptions.

Needless to say that's basically throwing away the benefits of the fact that c# is a strongly type language.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • Usage is just passing key value pairs of type string, int. That's exactly what an anonymous type is so I get my type safety. You use lots of calls just like this in razor code but no one complains about type safety, right? But I do understand my point here is sort of contradicting the very request I'm making. :) – BVernon Oct 16 '18 at 06:52
1

Use dynamic if you don't know the type of object before execution

svoychik
  • 1,188
  • 1
  • 8
  • 19
1

Well, there are a few cons and pros of using Dictionary here (mostly pros)

Pros:

  • It doesn't require additional logics
  • You're using benefits of C# as strongly typed language and type check exceptions are thrown at compile time
  • It is efficient

Cons:

  • It requires to write more code and is less flexible

If you have tons of calls where you pass dictionaries and performance is not your main concern you might want to create another overload for your method that accepts anonymous object, checks it, and creates a dictionary out of it:

public void MyMethod(object obj)
{
   if (!obj.IsAnonymousType())
   {
      throw new ArgumentException($"Object of this type is not supported!");
   }
   MyMethod(obj.ToDictionary<int>());
}

public void MyMethod(IDictionary<string, int> dict)
{
    // your code here...
}

...

public static class ObjHelper
{
    public static IDictionary<string, T> ToDictionary<T>(this object obj)
    {
        var objType = obj.GetType();

        // This call is optimized by compiler
        var props = objType.GetProperties();

        if (typeof(T) == typeof(object))
        {
            // we don't need to check if property is of certain type
            return props?.ToDictionary(p => p.Name, p => (T)p.GetValue(obj)) ?? new Dictionary<string, T>();
        }
        // It will ignore all types except of T
        return props?.Where(p => p.PropertyType == typeof(T)).ToDictionary(p => p.Name, p => (T)p.GetValue(obj)) ?? new Dictionary<string, T>();
    }

    public static bool IsAnonymousType(this object obj)
    {
        var type = obj.GetType();

        if (type == null)
        {
            throw new ArgumentNullException("type");
        }

        return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
               && type.IsGenericType && type.Name.Contains("AnonymousType")
               && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
               && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
    }
}

And call it:

MyMethod(new 
{
   foo = 15,
   bar = 8
})

Let's compare to normal dict call:

MyMethod(new Dictionary<string, int>() 
{
   { "foo", 15 },
   { "bar", 8 },
})

Average performance for 100000 operations in ms:

  • call with anonymous class: 270
  • call with Dictionary: 10
Fabjan
  • 13,506
  • 4
  • 25
  • 52