【问题标题】:dynamic does not contain a definition for a property from a project reference动态不包含项目引用中的属性定义
【发布时间】:2012-03-14 00:54:52
【问题描述】:

我收到一条错误消息:

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

所有代码也在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 项目中运行良好,但如果我添加 ConsoleApplication2 并引用 ConsoleApplication1 并添加完全相同的代码

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}

这是屏幕截图:

我正在做类似的事情并尝试从测试项目中调用电影函数。

【问题讨论】:

标签: c# .net dynamic dynamicobject


【解决方案1】:

Jahamal 的回答没有说​​明为什么您会收到错误消息。原因是匿名类对程序集来说是internal。关键字dynamic 不允许您绕过成员可见性。

解决方法是将匿名类替换为命名的公共类。

这是另一个很好的例子来解释原因和another possible solution

data2.Person 调用失败的原因是data2 的类型信息在运行时不可用。它不可用的原因是因为匿名类型不是公共的。当该方法返回该匿名类型的实例时,它会返回一个System.Object,它引用了一个匿名类型的实例——该类型的信息对主程序不可用。动态运行时尝试在对象上查找名为Person 的属性,但无法从它拥有的类型信息中解析它。因此,它会引发异常。对data.Name 的调用工作正常,因为Person 是一个公共类,该信息可用并且可以轻松解决。

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

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

【讨论】:

  • 请您在回答中引用您的出处好吗?
  • @d3dave 可以测试答案中的两个声明。可以在 .NET 反编译器中检查类可见性。可以在具有不同可见性成员的测试类上检查 dynamic 的访问规则。
  • 这是为什么 OP 所做的事情是一个问题的真正答案。
  • 我无法让它在同为 netcoreapp1.1 的源项目和测试项目之间工作。知道这只是我的错还是在 .NET Core 中不起作用?
【解决方案2】:

您需要使用 ExpandoObject

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

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

【讨论】:

  • 他费了很大的力气才写出了一个详细的问题,如果按照 Robert 的建议,让他知道为什么会出错,那就太好了
  • 您似乎不能将内联初始化程序功能与 expando 对象一起使用?
  • 应该在哪里使用 ExpandoObject?用于创建动态对象或解析动态对象?
  • 我不得不搜索更多信息,因为罗伯特的回答很有帮助,但我需要更深入的了解。 Oreilly 在这里有一篇关于动态类型的好文章:oreilly.com/learning/building-c-objects-dynamically
【解决方案3】:

就我而言,我有一个在 Visual Studio 上创建的单元测试项目,并且在很多情况下我需要在数据层库上测试方法。我不想全部更改,所以我将测试程序集标记为朋友:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

这样就解决了。

例子:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

参考资料:

【讨论】:

  • 原因是 Alexander Stepaniuk 所说的。您的评论是解决方案。谢谢!
  • 我无法让它在 netcoreapp1.1 项目之间工作,不确定是不是我做错了。
  • 非常感谢Jelgab!现在我不必用 ExpanoObject 替换动态!我在我的单元测试中使用依赖注入,我无法使用动态并让它在单元测试项目中工作。但这解决了它!
  • 请注意,如果是这种情况,您(开发人员)必须将其添加到创建匿名类型的相反项目中,或者两者都添加。
【解决方案4】:

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

'content' 是 json 字符串

此代码抛出错误:

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

此代码有效。像这样使用 ExpandoObject 插入动态:

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

【讨论】:

    【解决方案5】:

    我迟到了,但我是这样做的。

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

    【讨论】:

      猜你喜欢
      • 2020-08-13
      • 2021-07-19
      • 1970-01-01
      • 2014-10-21
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 2015-11-27
      • 2015-09-17
      相关资源
      最近更新 更多