动态不包含项目引用中属性的定义


91

我收到一条错误消息:

“对象”不包含“标题”的定义

所有代码也都在github上

我有一个看起来像这样的ConsoleApplication1

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));
        }
    }
} 

Movie.cs

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

它可以从SAME项目正常工作,但是如果我添加对ConsoleApplication1的引用的ConsoleApplication2并添加完全相同的代码

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));
        }
    }
}

我收到一个错误:

“对象”不包含“标题”的定义**

即使它在动态对象中。

  • o.Title'o.Title'引发了类型为'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'动态的异常{Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

这是一个屏幕截图: 在此处输入图片说明

我正在做这样的事情,并试图从测试项目中调用movie函数。


Answers:


79

您需要使用ExpandoObject

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

 Console.WriteLine(m.PrintMovie(o));

28
他遇到了很多麻烦,提出了一个详尽的问题,如罗伯特建议的那样
Luis Ferrao 2014年

2
似乎无法将内联初始化功能与expando对象一起使用?
罗伯托·波尼尼

1
在哪里应该使用ExpandoObject?用于创建动态对象还是用于解析动态对象?
侯赛因·阿卡贾尼

因为罗伯特的回答很有帮助,所以我不得不搜索更多信息,但是我需要更深刻的理解。Oreilly在这里有一篇关于动态类型的好文章:oreilly.com/learning/building-c-objects-dynamically
Billy Willoughby

137

Jahamal的答案没有说明为什么得到此错误。原因是匿名类属于internal程序集。关键字dynamic不允许您绕过成员可见性。

解决方案是用命名的公共类替换匿名类。

这是另一个很好的例子,解释了原因以及另一个可能的解决方案

调用data2.Person失败的原因是的类型信息data2在运行时不可用。它不可用的原因是因为匿名类型不是公共的。当该方法返回该匿名类型的实例时,它返回一个System.Object,它引用一个匿名类型的实例-该类型的信息对主程序不可用。动态运行时试图找到Person在对象上调用的属性,但是无法从其拥有的类型信息中解析它。因此,它引发异常。data.Name由于Person是公开类,因此对to的调用效果很好,因为该信息可用并且可以轻松解决。

在以下任何情况下(如果不更多),这可能会影响您:

  1. 您正在使用返回非公开的,非内部的类型System.Object。2.您将通过公共基本类型返回一个非公共的,非内部的派生类型,并访问该派生类型中不属于该基本类型的属性。3.您将从其他程序集中返回包装在匿名类型中的任何内容。

1
您能在答案中引用您的消息来源吗?
d3dave

@ d3dave答案中的两个声明可以被测试。可以在.NET反编译器中检查类的可见性。dynamic可以在具有不同可见性的成员的测试类中检查其访问规则。
罗伯特·瓦赞(RoyalVažan)2015年

3
这是为什么OP所做的事情有问题的真正答案。
Matti Virkkunen '17

1
我无法使它在都是netcoreapp1.1的源代码和测试项目之间工作。知道是我的错还是在.NET Core中不起作用?
Anthony Mastrean '17

27

就我而言,我有一个在Visual Studio上创建的单元测试项目,在很多情况下,我需要在数据层库上测试方法。我不想更改所有组件,因此我使用以下命令将测试程序集标记为好友:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

这就解决了。

例:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

参考文献:


1
原因是亚历山大·斯蒂帕努克(Alexander Stepaniuk)所说的。您的评论就是解决方案。谢谢!
Pato Loco,2015年

我不能让它在netcoreapp1.1项目之间工作,不知道这是否是我做错了。
Anthony Mastrean '17

非常感谢Jelgab!现在,我不必用ExpanoObject替代dynamic!我在单元测试中使用了依赖注入,但无法使用动态功能,并且无法在单元测试项目中使用它。但这解决了!
ShameWare '18

请注意,您(开发人员)必须将其添加到要从其创建匿名类型的相反项目中,或者如果是这样的话,则添加到相反的项目中。
ryanwebjackson

0

就我而言,我有一个xUnit测试项目。

其中“内容”是json字符串

这段代码抛出错误:

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

此代码有效。像这样使用具有动态功能的ExpandoObject

dynamic parsed = JsonConvert.DeserializeObject<ExpandoObject>(content);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.