112

I am getting an error that says:

'object' does not contain a definition for 'Title'

all the code is also on github

I have a ConsoleApplication1 that looks like this

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Movie m = new Movie();
            var o = new { Title = "Ghostbusters", Rating = "PG" };
            Console.WriteLine(m.PrintMovie(o));
        }
    }
} 

and Movie.cs

public class Movie : DynamicObject
{
    public string PrintMovie(dynamic o)
    {
        return string.Format("Title={0} Rating={1}", o.Title, o.Rating);
    }
} 

it works fine from the SAME project, but if I add ConsoleApplication2 with a reference to ConsoleApplication1 and add the Exact same code

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Movie m = new Movie();
            var o = new { Title = "Ghostbusters", Rating = "PG" };
            Console.WriteLine(m.PrintMovie(o));
        }
    }
}

I get an error:

'object' does not contain a definition for 'Title'**

even though it is in the dynamic object.

  • o.Title 'o.Title' threw an exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' dynamic {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Here is a screen shot: enter image description here

I am doing something like this and trying to call the movie function from a test project.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
eiu165
  • 6,101
  • 10
  • 41
  • 59
  • 3
    possible duplicate of [C# ‘dynamic’ cannot access properties from anonymous types declared in another assembly](http://stackoverflow.com/questions/2630370/c-sharp-dynamic-cannot-access-properties-from-anonymous-types-declared-in-anot) – Jesse C. Slicer Feb 23 '12 at 16:22

5 Answers5

171

Jahamal's answer doesn't say why you get the error. The reason is that the anonymous class is internal to the assembly. Keyword dynamic doesn't allow you to bypass member visibility.

The solution is to replace the anonymous class with named public class.

Here's another good example explaining the reason and another possible solution.

The reason the call to data2.Person fails is that the type information of data2 is not available at runtime. The reason it's not available is because anonymous types are not public. When the method is returning an instance of that anonymous type, it's returning a System.Object which references an instance of an anonymous type - a type whose info isn't available to the main program. The dynamic runtime tries to find a property called Person on the object, but can't resolve it from the type information it has. As such, it throws an exception. The call to data.Name works fine since Person is a public class, that information is available and can be easily resolved.

This can affect you in any of the following cases (if not more):

  1. You're returning a non-public, non-internal type using System.Object. 2. You're returning a non-public, non-internal derived type via a public base type and accessing a property in the derived type that's not in the base type. 3. You're returning anything wrapped inside an anonymous type from a different assembly.
danronmoon
  • 3,814
  • 5
  • 34
  • 56
Robert Važan
  • 3,399
  • 2
  • 25
  • 31
  • 1
    Could you cite your source in your answer, please? – d3dave Jun 25 '15 at 07:07
  • 1
    @d3dave The two claims in the answer can be tested. Class visibility can be checked in .NET decompiler. Access rules for `dynamic` can be checked on a test class with members of varying visibility. – Robert Važan Jun 25 '15 at 16:31
  • 3
    This is the real answer to why what OP was doing is a problem. – Matti Virkkunen May 08 '17 at 10:47
  • 1
    I can't get this to work between a source and test project that are both netcoreapp1.1. Any idea if it's just my fault or if this doesn't work in .NET Core? – Anthony Mastrean Nov 01 '17 at 18:32
100

You need to use an ExpandoObject

 dynamic o = new ExpandoObject();
 o.Title = "Ghostbusters";
 o.Rating = "PG";

 Console.WriteLine(m.PrintMovie(o));
JamahalSOF
  • 1,138
  • 1
  • 8
  • 6
  • 36
    He went through a lot of trouble to write an elaborate question, it would be nice to have let him know why he's getting the error, as Robert suggests – Luis Ferrao Sep 19 '14 at 08:45
  • 4
    Doesn't seem you can use the inline initializer functionality with expando object? – Roberto Bonini Jan 06 '15 at 16:31
  • 1
    Where should use ExpandoObject? for creating a dynamic object or for parsing a dynamic object? – Hosein Aqajani Sep 29 '17 at 14:58
  • 1
    I had to search for more information since Robert's answer was helpful but I needed a deeper understanding. Oreilly had a good article on dynamic types here: https://www.oreilly.com/learning/building-c-objects-dynamically – Billy Willoughby Jun 06 '18 at 15:08
37

In my case I had a Unit Test project that I created on Visual Studio and a lot of cases where I needed to test methods on a data layer library. I didn't want to change all of them so I marked the test assembly as a friend by using:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

And that solved it.

Example:

using System.Runtime.CompilerServices;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[assembly: InternalsVisibleTo( "MyDataLayerAssembly" )]
namespace MyUnitTestProject.DataTests
{

   [TestClass]
   public class ContactTests
   {
      ...

References:

Dave Anderson
  • 11,836
  • 3
  • 58
  • 79
Jelgab
  • 1,840
  • 19
  • 12
  • 1
    The reason is what Alexander Stepaniuk said. Your comment is the solution. Thanks! – Pato Loco May 12 '15 at 18:22
  • 1
    I can't get this to work between netcoreapp1.1 projects, not sure if it's something I'm doing incorrectly. – Anthony Mastrean Nov 01 '17 at 18:28
  • Huge Thanks Jelgab! Now I don't have to replace dynamic with ExpanoObject! I'm using dependency injection in my unit tests and I was unable to use dynamic and have it work from the unit test project. But this solved it! – ShameWare Apr 18 '18 at 19:22
  • Note that you (the developer) has to add this in the opposite project from which the anonymous types are being created, or both, if that is the case. – ryanwebjackson Feb 20 '19 at 20:05
5

In my case I have a xUnit test project.

Where 'content' is a json string.

This code throws error:

dynamic parsed = JsonConvert.DeserializeObject<dynamic>(content);

This code works. Use ExpandoObject insted of dynamic like this:

dynamic parsed = JsonConvert.DeserializeObject<ExpandoObject>(content);
Guilherme Ferreira
  • 1,503
  • 2
  • 18
  • 31
0

I am way late to the party, but here is a way I did it.

dynamic myObject = GetSomeObject();

//check if myObject is a special Object
(if myObject is specialObject)
{
    string specialPropery = ((specialObject))myObject).SpecialProperty;
    Console.WriteLine("The object is a special type. SpecialPropery: {specialPropery }");
}
else
{
    Console.WriteLine("The object normal type.");
}
Blee
  • 24
  • 4