Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dynamic C#和#x2018;动态’;无法从另一个程序集中声明的匿名类型访问属性_Dynamic_C# 4.0_Anonymous Types - Fatal编程技术网

Dynamic C#和#x2018;动态’;无法从另一个程序集中声明的匿名类型访问属性

Dynamic C#和#x2018;动态’;无法从另一个程序集中声明的匿名类型访问属性,dynamic,c#-4.0,anonymous-types,Dynamic,C# 4.0,Anonymous Types,只要我的classclasssameasemassembly与class程序在同一个程序集中,下面的代码就可以正常工作。 但是当我将classclasssameasembly移动到一个单独的程序集时,会抛出一个RuntimeBinderException(见下文)。 有可能解决吗 using System; namespace ConsoleApplication2 { public static class ClassSameAssembly { public

只要我的classclasssameasemassembly与class程序在同一个程序集中,下面的代码就可以正常工作。 但是当我将class
classsameasembly
移动到一个单独的程序集时,会抛出一个
RuntimeBinderException
(见下文)。 有可能解决吗

using System;

namespace ConsoleApplication2
{
    public static class ClassSameAssembly
    {
        public static dynamic GetValues()
        {
            return new
            {
                Name = "Michael", Age = 20
            };
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var d = ClassSameAssembly.GetValues();
            Console.WriteLine("{0} is {1} years old", d.Name, d.Age);
        }
    }
}
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
“对象”不包含“名称”的定义

at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at ConsoleApplication2.Program.Main(String[] args) in C:\temp\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 23

我认为问题在于匿名类型是作为
内部
生成的,因此绑定器并不真正“知道”它本身

尝试改用ExpandoObject:

public static dynamic GetValues()
{
    dynamic expando = new ExpandoObject();
    expando.Name = "Michael";
    expando.Age = 20;
    return expando;
}
我知道这有点难看,但这是目前我能想到的最好的。。。我认为您甚至不能使用对象初始值设定项,因为它的强类型为
ExpandoObject
,编译器不知道如何处理“Name”和“Age”。您可以这样做:

 dynamic expando = new ExpandoObject()
 {
     { "Name", "Michael" },
     { "Age", 20 }
 };
 return expando;
但这并没有好多少

您可能会编写一个扩展方法,通过反射将匿名类型转换为具有相同内容的expando。然后你可以写:

return new { Name = "Michael", Age = 20 }.ToExpando();

但这很可怕:(

您可以使用
[assembly:InternalsVisibleTo(“您的AssemblyName”)]
使您的程序集内部可见。

我遇到了一个类似的问题,我想补充一下Jon Skeets的回答:还有另一个选择。我发现的原因是我意识到Asp MVC3中的许多扩展方法使用匿名类作为输入来提供html属性(new{alt=“Image alt”,style=“padding top:5px”}=>

无论如何-这些函数使用RouteValueDictionary类的构造函数。我自己也尝试过,而且确实有效-尽管只有第一级(我使用了多级结构)。因此-在代码中,这将是:

object o = new {
    name = "theName",
    props = new {
        p1 = "prop1",
        p2 = "prop2"
    }
}
SeparateAssembly.TextFunc(o)

//In SeparateAssembly:
public void TextFunc(Object o) {
  var rvd = new RouteValueDictionary(o);

//Does not work:
Console.WriteLine(o.name);
Console.WriteLine(o.props.p1);

//DOES work!
Console.WriteLine(rvd["name"]);

//Does not work
Console.WriteLine(rvd["props"].p1);
Console.WriteLine(rvd["props"]["p1"]);
var d = ClassSameAssembly.GetValues().ToDynamic();
那么…这里到底发生了什么?在RouteValueDictionary中窥探一下就会发现以下代码(上面的值~=o):

因此,使用TypeDescriptor.GetProperties(o),我们将能够获得属性和值,尽管匿名类型在单独的程序集中被构造为内部!当然,这将很容易扩展,使其递归。如果需要,还可以创建扩展方法

希望这有帮助


/Victor

这里是扩展对象的扩展方法的一个基本版本,我确信它有改进的余地

    public static ExpandoObject ToExpandoObject(this object value)
    {
        // Throw is a helper in my project, replace with your own check(s)
        Throw<ArgumentNullException>.If(value, Predicates.IsNull, "value");

        var obj = new ExpandoObject() as IDictionary<string, object>;

        foreach (var property in value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            obj.Add(property.Name, property.GetValue(value, null));
        }

        return obj as ExpandoObject;
    }

    [TestCase(1, "str", 10.75, 9.000989, true)]
    public void ToExpandoObjectTests(int int1, string str1, decimal dec1, double dbl1, bool bl1)
    {
        DateTime now = DateTime.Now;

        dynamic value = new {Int = int1, String = str1, Decimal = dec1, Double = dbl1, Bool = bl1, Now = now}.ToExpandoObject();

        Assert.AreEqual(int1, value.Int);
        Assert.AreEqual(str1, value.String);
        Assert.AreEqual(dec1, value.Decimal);
        Assert.AreEqual(dbl1, value.Double);
        Assert.AreEqual(bl1, value.Bool);
        Assert.AreEqual(now, value.Now);
    }
publicstaticexpandoobject到ExpandoObject(此对象值)
{
//Throw是我的项目中的帮助者,请用您自己的支票替换
If(value,Predicates.IsNull,“value”);
var obj=作为IDictionary的新ExpandooObject();
foreach(value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)中的var属性)
{
Add(property.Name,property.GetValue(value,null));
}
将obj返回为ExpandoObject;
}
[测试用例(1,“str”,10.75,9.000989,true)]
expandoobjecttests的公共void(int-int1、字符串str1、十进制dec1、双dbl1、bool-bl1)
{
DateTime now=DateTime.now;
动态值=new{Int=int1,String=str1,Decimal=dec1,Double=dbl1,Bool=bl1,Now=Now}.ToExpandoObject();
aresequal(int1,value.Int);
aresequal(str1,value.String);
Assert.AreEqual(dec1,value.Decimal);
AreEqual(dbl1,value.Double);
arenequal(bl1,value.Bool);
arest.AreEqual(现在,value.now);
}

勇敢者的扩展方法(在Jon的回答中提到)

public static class ExtensionMethods
{
    public static ExpandoObject ToExpando(this object obj)
    {
        IDictionary<string, object> expando = new ExpandoObject();
        foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(obj))
        {
            var value = propertyDescriptor.GetValue(obj);
            expando.Add(propertyDescriptor.Name, value == null || new[]
            {
                typeof (Enum),
                typeof (String),
                typeof (Char),
                typeof (Guid),
                typeof (Boolean),
                typeof (Byte),
                typeof (Int16),
                typeof (Int32),
                typeof (Int64),
                typeof (Single),
                typeof (Double),
                typeof (Decimal),
                typeof (SByte),
                typeof (UInt16),
                typeof (UInt32),
                typeof (UInt64),
                typeof (DateTime),
                typeof (DateTimeOffset),
                typeof (TimeSpan),
            }.Any(oo => oo.IsInstanceOfType(value))
                ? value
                : value.ToExpando());
        }

        return (ExpandoObject)expando;
    }
}
公共静态类扩展方法
{
公共静态扩展对象扩展到扩展对象(此对象对象)
{
IDictionary expando=新的ExpandoObject();
foreach(TypeDescriptor.GetProperties(obj)中的PropertyDescriptor PropertyDescriptor)
{
var值=propertyDescriptor.GetValue(obj);
expando.Add(propertyDescriptor.Name,value==null | | new[]
{
类型(枚举),
类型(字符串),
类型(字符),
类型(Guid),
类型(布尔),
类型(字节),
类型(Int16),
类型(Int32),
类型(Int64),
类型(单个),
类型(双),
类型(十进制),
类型(SByte),
类型(UInt16),
类型(UInt32),
类型(UInt64),
类型(日期时间),
类型(日期时间偏移量),
类型(时间跨度),
}.Any(oo=>oo.IsInstanceOfType(值))
价值
:value.ToExpando());
}
返回(ExpandoObject)expando;
}
}

更清洁的解决方案是:

object o = new {
    name = "theName",
    props = new {
        p1 = "prop1",
        p2 = "prop2"
    }
}
SeparateAssembly.TextFunc(o)

//In SeparateAssembly:
public void TextFunc(Object o) {
  var rvd = new RouteValueDictionary(o);

//Does not work:
Console.WriteLine(o.name);
Console.WriteLine(o.props.p1);

//DOES work!
Console.WriteLine(rvd["name"]);

//Does not work
Console.WriteLine(rvd["props"].p1);
Console.WriteLine(rvd["props"]["p1"]);
var d = ClassSameAssembly.GetValues().ToDynamic();
它现在是一个扩展对象

请记住参考:

Microsoft.CSharp.dll

下面的解决方案在我的控制台应用程序项目中对我有效

将此[assembly:InternalsVisibleTo(“您的AssemblyName”)] 在单独项目的\Properties\AssemblyInfo.cs中,函数返回动态对象


“YourAssemblyName”是调用项目的程序集名称。您可以通过在调用项目中执行assembly.GetExecutionGassembly().FullName来获得该名称。

如果您已经在项目中使用Newtonsoft.Json(或者您愿意为此添加它),您可以实现Jon Skeet在中提到的可怕的扩展方法,如下所示:

public static class ObjectExtensions
{
    public static ExpandoObject ToExpando(this object obj)
        => JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(obj));
}
公共静态类ObjectExtensions
{
公共静态扩展对象扩展到扩展对象(此对象对象)
=>JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj));
}

StackTrace:System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite,T0 arg0)的CallSite.Target(Closure,CallSite,Object)和ConsoleApplication2.Program.Main(Stri