2012-04-25 8 views
6

EDITAR: reiniciar Visual Studio solucionó este problema sin cambios de código.objeto dinámico: el campo de informes de tiempo de ejecución no está presente pero puede verlo en el depurador?


que tienen un controlador configSection que utiliza tipos dinámicos y un objeto expando. La prueba falla al informar 'objeto' no contiene una definición para 'SportName'. Intenté replicar en una consola que saca el manejador ConfigSection de la ecuación, pero lo que parece ser el código equivalente funciona bien. Estoy perplejo.

ver más abajo para la prueba, ConfigurationSectionHandler y xml de configuración

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> 

ACTUALIZACIÓN - Seguimiento de la pila:

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

El código parece correcto y confirma que funciona bien en la consola. Prueba a depurar la prueba, y 'tic' maneja las excepciones. Luego comience a buscar en la parte superior de la pila de llamadas (muestre el código externo) inspeccionando a los lugareños. – leppie

+0

Si se refiere a marcar 'Lanzado' en el diálogo Depurar> Excepción, se rompe en el mismo punto ... se ha actualizado con la pila de llamadas, thx –

+1

Sí, quiero decir eso. Ahora cuando se rompe allí, inspecciona a los lugareños en los 2 marcos superiores. También puede tal vez inspeccionar el IL de las asambleas para ver si algo anda mal. – leppie

Respuesta

3

ToSport devuelve un tipo anónimo en lugar de un ExpandoObject. Debe tener cuidado al convertir un tipo anónimo en dinámico, porque esos tipos tienen un modificador de acceso de internal. Por lo tanto, si cruza los límites de ensamblaje, el tiempo de ejecución no verá ninguna propiedad accesible. Pruebe:

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

    } 
+0

Eso explicaría el problema que experimenté, aunque no explica por qué reiniciar VS lo solucionó. Extraño. –

+1

Diferentes tipos de compilaciones a veces pueden oscurecerse donde se encuentra un límite de ensamblaje. Por ejemplo, ASP.NET tiene páginas compiladas sobre la marcha que pueden agruparse aleatoriamente en diferentes conjuntos. Tampoco sé por qué VS lo solucionó, pero sí sé que es una buena práctica reemplazar los tipos anónimos devueltos por el lanzamiento dinámico con ExpandoObjects. – jbtule

+0

¡Un buen consejo, gracias! –

Cuestiones relacionadas