dynamic object - runtime reports field not present but can see it in debugger?

时光毁灭记忆、已成空白 提交于 2019-12-08 21:03:34

问题


EDIT : restarting visual studio fixed this issue with no code changes.


I have a ConfigSection handler that uses dynamic types and an expando object. The test fails reporting 'object' does not contain a definition for 'SportName'. I have tried to replicate in a console taking the ConfigSection handler out of the equation but what looks like the equivalent code works fine. I'm stumped.

See below for test, ConfigurationSectionHandler and config xml

public class SportSection : IConfigurationSectionHandler
{
    public object Create(object parent, object configContext, XmlNode section)
    {
        var doc = XDocument.Parse(section.OuterXml);
        var root = (XElement)doc.FirstNode;

        try
        {
            var sportList = root.Element("sportList").Elements("sport").Select(ToSport);

            dynamic config = new ExpandoObject();
            config.SportList = sportList;

            return config;
        }
        catch (Exception ex)
        {
            throw new ConfigurationErrorsException("Invalid SportSection configuration", ex);
        }
    }

    private static dynamic ToSport(XElement sportElement)
    {
        try
        {
            var getAttrib = new Func<XElement, string, string>((x, atr) => x.Attribute(atr).Value);
            var getDictionary =
                new Func<IEnumerable<XElement>, IDictionary<string, string>>(elems => elems.ToDictionary(x => x.Attribute("name").Value, y => y.Attribute("value").Value));

            return new
            {
                SportName = sportElement.Attribute("name").Value,
                EventProperties = getDictionary(sportElement.Element("eventProperties").Elements("property")),
                CompetitionProperties = getDictionary(sportElement.Element("competitionProperties").Elements("property")),
                MappedMarkets = sportElement.Element("mapping").Elements("market").Select(x => new MappedMarket() { Type = getAttrib(x, "type"), MappedType = getAttrib(x, "mappedType") })
            };
        }
        catch (Exception ex)
        {

            throw ex;
        }

    }
}


[Test]
    public void GoodConfig()
    {
        var document = new XmlDocument();
        document.LoadXml(Resources.ValidSportSectionConfig);

        var config = new SportSection().Create(null, null, document) as dynamic;

        IEnumerable<dynamic> sportList = config.SportList;

        Assert.AreEqual(1, sportList.Count());
        //Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : 'object' does not contain a definition for 'SportName'
        Assert.AreEqual("Baseball", sportList.Select(x => (string) x.SportName).First()); 

        var eventProperties = sportList.First(x => x.SportName == "Baseball").EventProperties as IDictionary<string, string>;

        Assert.AreEqual(2, eventProperties.Count);
        Assert.AreEqual("BSB", eventProperties["SportId"]);
        Assert.AreEqual("THA", eventProperties["CompetitorReferenceId"]);

        var compProps = sportList.First(x => x.SportName == "Baseball").CompetitionProperties as IDictionary<string, string>;
        Assert.AreEqual(2, compProps.Count);
        Assert.AreEqual("BSB", compProps["SportId"]);
        Assert.AreEqual("CUP", compProps["CompetitionOrgMethodId"]);

        var mappedMarkets = (sportList.First(x => x.SportName == "Baseball").MappedMarkets as IEnumerable<MappedMarket>).ToList();
        Assert.AreEqual(2, mappedMarkets.Count());
        Assert.AreEqual("match_winner" , mappedMarkets[0].Type);
        Assert.AreEqual("BSBAO", mappedMarkets[0].MappedType);
        Assert.AreEqual("handicap", mappedMarkets[0].Type);
        Assert.AreEqual("BSBAQ", mappedMarkets[0].MappedType);
    }

<sportSettings>
  <sportList>
    <sport name="Baseball">
    <eventProperties>
      <property name="SportId" value="BSB"></property>
      <property name="CompetitorReferenceId" value="THA"></property>
    </eventProperties>
    <competitionProperties>
      <property name="SportId" value="BSB" />
      <property name="CompetitionOrgMethodId" value="CUP" />
    </competitionProperties>
    <mapping>
      <market type="match_winner" mappedType="BSBAO" />
      <market type="handicap" mappedType="BSBAQ" />
    </mapping>
    </sport>
  </sportList>
</sportSettings>

UPDATE - Stack Trace:

at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at SS.Integration.EVenue.WindowsService.UnitTests.Configuration.SportSectionTests.<GoodConfig>b__11(Object x) in C:\_Git\SS.Integration.EVenue\SS.Integration.EVenue.WindowsService.UnitTests\Configuration\SportSectionTests.cs:line 35

回答1:


ToSport returns an anonymous type rather than an ExpandoObject. You have to be careful when you cast an anonymous type to dynamic, because those types have an access modifier of internal. Thus, if you cross assembly boundaries the runtime won't see any accessable properties. Try:

 private static dynamic ToSport(XElement sportElement)
    {
        try
        {
            var getAttrib = new Func<XElement, string, string>((x, atr) => x.Attribute(atr).Value);
            var getDictionary =
                new Func<IEnumerable<XElement>, IDictionary<string, string>>(elems => elems.ToDictionary(x => x.Attribute("name").Value, y => y.Attribute("value").Value));


            dynamic n = new ExpandoObject();
            n.SportName = sportElement.Attribute("name").Value;
            n.EventProperties = getDictionary(sportElement.Element("eventProperties").Elements("property"));
            n.CompetitionProperties = getDictionary(sportElement.Element("competitionProperties").Elements("property"));
            n.MappedMarkets = sportElement.Element("mapping").Elements("market").Select(x => new MappedMarket() { Type = getAttrib(x, "type"), MappedType = getAttrib(x, "mappedType") });

            return n;
        }
        catch (Exception ex)
        {

            throw ex;
        }

    }


来源:https://stackoverflow.com/questions/10316344/dynamic-object-runtime-reports-field-not-present-but-can-see-it-in-debugger

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!