Removing IMapper (backport)

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2011-10-05 13:59:24 -07:00
parent 7f56999a0b
commit 73d44afb2c
22 changed files with 455 additions and 231 deletions

View File

@@ -257,6 +257,8 @@
<Compile Include="XmlRpc\Models\XRpcMethodCall.cs" />
<Compile Include="XmlRpc\Models\XRpcMethodResponse.cs" />
<Compile Include="XmlRpc\Models\XRpcStruct.cs" />
<Compile Include="XmlRpc\Services\IXmlRpcReader.cs" />
<Compile Include="XmlRpc\Services\IXmlRpcWriter.cs" />
<Compile Include="XmlRpc\Services\XmlRpcReader.cs" />
<Compile Include="XmlRpc\Services\XmlRpcWriter.cs" />
<Compile Include="XmlRpc\XmlRpcContext.cs" />

View File

@@ -5,6 +5,7 @@ using System.Xml.Linq;
using Orchard.Caching;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.MetaData.Services;
using Orchard.Core.Settings.Metadata.Records;
using Orchard.Data;
using Orchard.Logging;
@@ -18,8 +19,7 @@ namespace Orchard.Core.Settings.Metadata {
private readonly IRepository<ContentTypeDefinitionRecord> _typeDefinitionRepository;
private readonly IRepository<ContentPartDefinitionRecord> _partDefinitionRepository;
private readonly IRepository<ContentFieldDefinitionRecord> _fieldDefinitionRepository;
private readonly IMapper<XElement, SettingsDictionary> _settingsReader;
private readonly IMapper<SettingsDictionary, XElement> _settingsWriter;
private readonly ISettingsFormatter _settingsFormatter;
public ContentDefinitionManager(
ICacheManager cacheManager,
@@ -27,15 +27,13 @@ namespace Orchard.Core.Settings.Metadata {
IRepository<ContentTypeDefinitionRecord> typeDefinitionRepository,
IRepository<ContentPartDefinitionRecord> partDefinitionRepository,
IRepository<ContentFieldDefinitionRecord> fieldDefinitionRepository,
IMapper<XElement, SettingsDictionary> settingsReader,
IMapper<SettingsDictionary, XElement> settingsWriter) {
ISettingsFormatter settingsFormatter) {
_cacheManager = cacheManager;
_signals = signals;
_typeDefinitionRepository = typeDefinitionRepository;
_partDefinitionRepository = partDefinitionRepository;
_fieldDefinitionRepository = fieldDefinitionRepository;
_settingsReader = settingsReader;
_settingsWriter = settingsWriter;
_settingsFormatter = settingsFormatter;
}
public ContentTypeDefinition GetTypeDefinition(string name) {
@@ -45,6 +43,38 @@ namespace Orchard.Core.Settings.Metadata {
});
}
public void DeleteTypeDefinition(string name) {
var record = _typeDefinitionRepository.Fetch(x => x.Name == name).SingleOrDefault();
// deletes the content type record associated
if (record != null) {
_typeDefinitionRepository.Delete(record);
}
// invalidates the cache
TriggerContentDefinitionSignal();
}
public void DeletePartDefinition(string name) {
// remove parts from current types
var typesWithPart = ListTypeDefinitions().Where(typeDefinition => typeDefinition.Parts.Any(part => part.PartDefinition.Name == name));
foreach (var typeDefinition in typesWithPart) {
this.AlterTypeDefinition(typeDefinition.Name, builder => builder.RemovePart(name));
}
// delete part
var record = _partDefinitionRepository.Fetch(x => x.Name == name).SingleOrDefault();
if (record != null) {
_partDefinitionRepository.Delete(record);
}
// invalidates the cache
TriggerContentDefinitionSignal();
}
public ContentPartDefinition GetPartDefinition(string name) {
return _cacheManager.Get(name ?? string.Empty, ctx => {
MonitorContentDefinitionSignal(ctx);
@@ -83,39 +113,6 @@ namespace Orchard.Core.Settings.Metadata {
Apply(contentPartDefinition, Acquire(contentPartDefinition));
}
public void DeleteTypeDefinition(string name) {
var record = _typeDefinitionRepository.Fetch(x => x.Name == name).SingleOrDefault();
// deletes the content type record associated
if (record != null) {
_typeDefinitionRepository.Delete(record);
}
// invalidates the cache
TriggerContentDefinitionSignal();
}
public void DeletePartDefinition(string name) {
// remove parts from current types
var typesWithPart = ListTypeDefinitions().Where(typeDefinition => typeDefinition.Parts.Any(part => part.PartDefinition.Name == name));
foreach (var typeDefinition in typesWithPart) {
this.AlterTypeDefinition(typeDefinition.Name, builder => builder.RemovePart(name));
}
// delete part
var record = _partDefinitionRepository.Fetch(x => x.Name == name).SingleOrDefault();
if (record != null) {
_partDefinitionRepository.Delete(record);
}
// invalidates the cache
TriggerContentDefinitionSignal();
}
private void MonitorContentDefinitionSignal(AcquireContext<string> ctx) {
ctx.Monitor(_signals.When(ContentDefinitionSignal));
}
@@ -153,7 +150,7 @@ namespace Orchard.Core.Settings.Metadata {
private void Apply(ContentTypeDefinition model, ContentTypeDefinitionRecord record) {
record.DisplayName = model.DisplayName;
record.Settings = _settingsWriter.Map(model.Settings).ToString();
record.Settings = _settingsFormatter.Map(model.Settings).ToString();
var toRemove = record.ContentTypePartDefinitionRecords
.Where(partDefinitionRecord => !model.Parts.Any(part => partDefinitionRecord.ContentPartDefinitionRecord.Name == part.PartDefinition.Name))
@@ -175,11 +172,11 @@ namespace Orchard.Core.Settings.Metadata {
}
private void Apply(ContentTypePartDefinition model, ContentTypePartDefinitionRecord record) {
record.Settings = Compose(_settingsWriter.Map(model.Settings));
record.Settings = Compose(_settingsFormatter.Map(model.Settings));
}
private void Apply(ContentPartDefinition model, ContentPartDefinitionRecord record) {
record.Settings = _settingsWriter.Map(model.Settings).ToString();
record.Settings = _settingsFormatter.Map(model.Settings).ToString();
var toRemove = record.ContentPartFieldDefinitionRecords
.Where(partFieldDefinitionRecord => !model.Fields.Any(partField => partFieldDefinitionRecord.Name == partField.Name))
@@ -204,7 +201,7 @@ namespace Orchard.Core.Settings.Metadata {
}
private void Apply(ContentPartFieldDefinition model, ContentPartFieldDefinitionRecord record) {
record.Settings = Compose(_settingsWriter.Map(model.Settings));
record.Settings = Compose(_settingsFormatter.Map(model.Settings));
}
ContentTypeDefinition Build(ContentTypeDefinitionRecord source) {
@@ -212,27 +209,27 @@ namespace Orchard.Core.Settings.Metadata {
source.Name,
source.DisplayName,
source.ContentTypePartDefinitionRecords.Select(Build),
_settingsReader.Map(Parse(source.Settings)));
_settingsFormatter.Map(Parse(source.Settings)));
}
ContentTypePartDefinition Build(ContentTypePartDefinitionRecord source) {
return new ContentTypePartDefinition(
Build(source.ContentPartDefinitionRecord),
_settingsReader.Map(Parse(source.Settings)));
_settingsFormatter.Map(Parse(source.Settings)));
}
ContentPartDefinition Build(ContentPartDefinitionRecord source) {
return new ContentPartDefinition(
source.Name,
source.ContentPartFieldDefinitionRecords.Select(Build),
_settingsReader.Map(Parse(source.Settings)));
_settingsFormatter.Map(Parse(source.Settings)));
}
ContentPartFieldDefinition Build(ContentPartFieldDefinitionRecord source) {
return new ContentPartFieldDefinition(
Build(source.ContentFieldDefinitionRecord),
source.Name,
_settingsReader.Map(Parse(source.Settings)));
_settingsFormatter.Map(Parse(source.Settings)));
}
ContentFieldDefinition Build(ContentFieldDefinitionRecord source) {

View File

@@ -1,17 +1,17 @@
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Xml.Linq;
using Orchard.Core.XmlRpc.Models;
using Orchard.Core.XmlRpc.Services;
using Orchard.Logging;
namespace Orchard.Core.XmlRpc.Controllers {
public class HomeController : Controller {
private readonly IMapper<XRpcMethodResponse, XElement> _writer;
private readonly IXmlRpcWriter _writer;
private readonly IEnumerable<IXmlRpcHandler> _xmlRpcHandlers;
public HomeController(
IMapper<XRpcMethodResponse, XElement> writer,
IXmlRpcWriter writer,
IEnumerable<IXmlRpcHandler> xmlRpcHandlers) {
_writer = writer;
_xmlRpcHandlers = xmlRpcHandlers;
@@ -29,7 +29,7 @@ namespace Orchard.Core.XmlRpc.Controllers {
if (methodResponse == null)
throw new HttpException(500, "TODO: xmlrpc fault");
var content = _writer.Map(methodResponse).ToString();
var content = _writer.MapMethodResponse(methodResponse).ToString();
return Content(content, "text/xml");
}

View File

@@ -2,32 +2,33 @@
using System.Web.Mvc;
using System.Xml;
using System.Xml.Linq;
using Orchard.Core.XmlRpc.Services;
using Orchard.Mvc.ModelBinders;
using IModelBinderProvider = Orchard.Mvc.ModelBinders.IModelBinderProvider;
namespace Orchard.Core.XmlRpc.Models {
public class ModelBinderProvider : IModelBinderProvider, IModelBinder {
private readonly IMapper<XElement, XRpcMethodCall> _mapper;
private readonly IXmlRpcReader _mapper;
public ModelBinderProvider(IMapper<XElement, XRpcMethodCall> mapper) {
public ModelBinderProvider(IXmlRpcReader mapper) {
_mapper = mapper;
}
public IEnumerable<ModelBinderDescriptor> GetModelBinders() {
return new[] {
new ModelBinderDescriptor {
ModelBinder =this,
Type=typeof(XRpcMethodCall)
ModelBinder = this,
Type = typeof(XRpcMethodCall)
}
};
}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
//Ah! xmlrpc is a value provider!!!
// Ah! xmlrpc is a value provider!!!
// TODO: refactor this?
using (var xmlReader = XmlReader.Create(controllerContext.HttpContext.Request.InputStream)) {
var element = XElement.Load(xmlReader);
return _mapper.Map(element);
return _mapper.MapToMethodCall(element);
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Xml.Linq;
using Orchard.Core.XmlRpc.Models;
namespace Orchard.Core.XmlRpc.Services {
/// <summary>
/// Abstraction to read XML and convert it to rpc entities.
/// </summary>
public interface IXmlRpcReader : IDependency {
/// <summary>
/// Maps an XML element to a rpc method call.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc method call.</returns>
XRpcMethodCall MapToMethodCall(XElement source);
/// <summary>
/// Maps an XML element to rpc data.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc data.</returns>
XRpcData MapToData(XElement source);
/// <summary>
/// Maps an XML element to a rpc struct.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc struct.</returns>
XRpcStruct MapToStruct(XElement source);
/// <summary>
/// Maps an XML element to a rpc array.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc array.</returns>
XRpcArray MapToArray(XElement source);
}
}

View File

@@ -0,0 +1,37 @@
using System.Xml.Linq;
using Orchard.Core.XmlRpc.Models;
namespace Orchard.Core.XmlRpc.Services {
/// <summary>
/// Abstraction to write XML based on rpc entities.
/// </summary>
public interface IXmlRpcWriter : IDependency {
/// <summary>
/// Maps a method response to XML.
/// </summary>
/// <param name="rpcMethodResponse">The method response to be mapped.</param>
/// <returns>The XML element.</returns>
XElement MapMethodResponse(XRpcMethodResponse rpcMethodResponse);
/// <summary>
/// Maps rpc data to XML.
/// </summary>
/// <param name="rpcData">The rpc data.</param>
/// <returns>The XML element.</returns>
XElement MapData(XRpcData rpcData);
/// <summary>
/// Maps a rpc struct to XML.
/// </summary>
/// <param name="rpcStruct">The rpc struct.</param>
/// <returns>The XML element.</returns>
XElement MapStruct(XRpcStruct rpcStruct);
/// <summary>
/// Maps a rpc array to XML.
/// </summary>
/// <param name="rpcArray">The rpc array.</param>
/// <returns>The XML element.</returns>
XElement MapArray(XRpcArray rpcArray);
}
}

View File

@@ -6,91 +6,120 @@ using System.Xml.Linq;
using Orchard.Core.XmlRpc.Models;
namespace Orchard.Core.XmlRpc.Services {
public class XmlRpcReader :
IMapper<XElement, XRpcMethodCall>,
IMapper<XElement, XRpcData>,
IMapper<XElement, XRpcStruct>,
IMapper<XElement, XRpcArray> {
/// <summary>
/// Abstraction to read XML and convert it to rpc entities.
/// </summary>
public class XmlRpcReader : IXmlRpcReader {
/// <summary>
/// Provides the mapping function based on a type name.
/// </summary>
private readonly IDictionary<string, Func<XElement, XRpcData>> _dispatch;
/// <summary>
/// Initializes a new instance of the <see cref="XmlRpcReader"/> class.
/// </summary>
public XmlRpcReader() {
_dispatch = new Dictionary<string, Func<XElement, XRpcData>>
{
{"i4",x=>new XRpcData<int> { Value = (int)x }},
{"int", x=>new XRpcData<int> { Value = (int)x }},
{"boolean", x=>new XRpcData<bool> { Value = ((string)x=="1") }},
{"string", x=>new XRpcData<string> { Value = (string)x }},
{"double", x=>new XRpcData<double> { Value = (double)x }},
{"dateTime.iso8601", x=> {
DateTime parsedDateTime;
// try parsing a "normal" datetime string then try what live writer gives us
if(!DateTime.TryParse(x.Value, out parsedDateTime)
&& !DateTime.TryParseExact(x.Value, "yyyyMMddTHH:mm:ss", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out parsedDateTime)) {
parsedDateTime = DateTime.Now;
}
return new XRpcData<DateTime> {Value = parsedDateTime};
}},
{"base64", x=>new XRpcData<byte[]> { Value = Convert.FromBase64String((string)x) }},
{"struct", x=>XRpcData.For(Map<XRpcStruct>(x))} ,
{"array", x=>XRpcData.For(Map<XRpcArray>(x))} ,
};
{
{ "i4", x => new XRpcData<int> { Value = (int)x } },
{ "int", x => new XRpcData<int> { Value = (int)x } },
{ "boolean", x => new XRpcData<bool> { Value = (string)x == "1" } },
{ "string", x => new XRpcData<string> { Value = (string)x } },
{ "double", x => new XRpcData<double> { Value = (double)x } },
{ "dateTime.iso8601", x => {
DateTime parsedDateTime;
// try parsing a "normal" datetime string then try what live writer gives us
if (!DateTime.TryParse(x.Value, out parsedDateTime)
&& !DateTime.TryParseExact(x.Value, "yyyyMMddTHH:mm:ss", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out parsedDateTime)) {
parsedDateTime = DateTime.Now;
}
return new XRpcData<DateTime> { Value = parsedDateTime };
} },
{ "base64", x => new XRpcData<byte[]> { Value = Convert.FromBase64String((string)x) } },
{ "struct", x => XRpcData.For(MapToStruct(x)) },
{ "array", x => XRpcData.For(MapToArray(x)) },
};
}
T2 Map<T2>(XElement t1) {
return ((IMapper<XElement, T2>)this).Map(t1);
}
XRpcData MapValue(XContainer t1) {
var element = t1.Elements().SingleOrDefault();
Func<XElement, XRpcData> dispatch;
if (_dispatch.TryGetValue(element.Name.LocalName, out dispatch) == false)
throw new ApplicationException("Unknown XmlRpc value type " + element.Name.LocalName);
return dispatch(element);
}
XRpcMethodCall IMapper<XElement, XRpcMethodCall>.Map(XElement source) {
/// <summary>
/// Maps an XML element to a rpc method call.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc method call.</returns>
public XRpcMethodCall MapToMethodCall(XElement source) {
return new XRpcMethodCall {
MethodName = (string)source.Element("methodName"),
Params = source.Elements("params").Elements("param").Select(Map<XRpcData>).ToList()
Params = source.Elements("params").Elements("param").Select(MapToData).ToList()
};
}
XRpcData IMapper<XElement, XRpcData>.Map(XElement source) {
/// <summary>
/// Maps an XML element to rpc data.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc data.</returns>
public XRpcData MapToData(XElement source) {
var value = source.Element("value");
if (value == null)
if (value == null) {
return new XRpcData();
}
var element = value.Elements().SingleOrDefault();
Func<XElement, XRpcData> dispatch;
if (_dispatch.TryGetValue(element.Name.LocalName, out dispatch) == false)
if (_dispatch.TryGetValue(element.Name.LocalName, out dispatch) == false) {
throw new ApplicationException("Unknown XmlRpc value type " + element.Name.LocalName);
}
return dispatch(element);
}
XRpcStruct IMapper<XElement, XRpcStruct>.Map(XElement source) {
/// <summary>
/// Maps an XML element to a rpc struct.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc struct.</returns>
public XRpcStruct MapToStruct(XElement source) {
var result = new XRpcStruct();
foreach (var member in source.Elements("member")) {
result.Members.Add(
(string)member.Element("name"),
MapValue(member.Element("value")));
}
return result;
}
XRpcArray IMapper<XElement, XRpcArray>.Map(XElement source) {
/// <summary>
/// Maps an XML element to a rpc array.
/// </summary>
/// <param name="source">The XML element to be mapped.</param>
/// <returns>The rpc array.</returns>
public XRpcArray MapToArray(XElement source) {
var result = new XRpcArray();
foreach (var value in source.Elements("data").Elements("value")) {
result.Data.Add(MapValue(value));
}
return result;
}
/// <summary>
/// Maps an XML container to rpc data.
/// </summary>
/// <param name="source">The XML container to be mapped.</param>
/// <returns>The rpc data.</returns>
private XRpcData MapValue(XContainer source) {
var element = source.Elements().SingleOrDefault();
Func<XElement, XRpcData> dispatch;
if (_dispatch.TryGetValue(element.Name.LocalName, out dispatch) == false) {
throw new ApplicationException("Unknown XmlRpc value type " + element.Name.LocalName);
}
return dispatch(element);
}
}
}
}

View File

@@ -3,69 +3,98 @@ using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.Core.XmlRpc.Models;
using Orchard.Validation;
namespace Orchard.Core.XmlRpc.Services {
public class XmlRpcWriter :
IMapper<XRpcMethodResponse, XElement>,
IMapper<XRpcStruct, XElement>,
IMapper<XRpcArray, XElement>,
IMapper<XRpcData, XElement> {
public XmlRpcWriter() {
_dispatch = new Dictionary<Type, Func<XRpcData, XElement>>
{
{typeof(int), p=>new XElement("int", (int)p.Value)},
{typeof(bool), p=>new XElement("boolean", (bool)p.Value?"1":"0")},
{typeof(string), p=>new XElement("string", p.Value)},
{typeof(double), p=>new XElement("double", (double)p.Value)},
{typeof(DateTime), p=>new XElement("dateTime.iso8601", ((DateTime)p.Value).ToString("yyyyMMddTHH:mm:ssZ"))},
{typeof(DateTime?), p=>new XElement("dateTime.iso8601", ((DateTime?)p.Value).Value.ToString("yyyyMMddTHH:mm:ssZ"))},
{typeof(byte[]), p=>new XElement("base64", Convert.ToBase64String((byte[])p.Value))},
{typeof(XRpcStruct), p=>Map((XRpcStruct)p.Value)},
{typeof(XRpcArray), p=>Map((XRpcArray)p.Value)},
};
}
/// <summary>
/// Abstraction to write XML based on rpc entities.
/// </summary>
public class XmlRpcWriter : IXmlRpcWriter {
/// <summary>
/// Provides the mapping function based on a type.
/// </summary>
private readonly IDictionary<Type, Func<XRpcData, XElement>> _dispatch;
XElement IMapper<XRpcMethodResponse, XElement>.Map(XRpcMethodResponse source) {
/// <summary>
/// Initializes a new instance of the <see cref="XmlRpcWriter"/> class.
/// </summary>
public XmlRpcWriter() {
_dispatch = new Dictionary<Type, Func<XRpcData, XElement>>
{
{ typeof(int), p => new XElement("int", (int)p.Value) },
{ typeof(bool), p => new XElement("boolean", (bool)p.Value ? "1" : "0") },
{ typeof(string), p => new XElement("string", p.Value) },
{ typeof(double), p => new XElement("double", (double)p.Value) },
{ typeof(DateTime), p => new XElement("dateTime.iso8601", ((DateTime)p.Value).ToString("yyyyMMddTHH:mm:ssZ")) },
{ typeof(DateTime?), p => new XElement("dateTime.iso8601", ((DateTime?)p.Value).Value.ToString("yyyyMMddTHH:mm:ssZ")) },
{ typeof(byte[]), p => new XElement("base64", Convert.ToBase64String((byte[])p.Value)) },
{ typeof(XRpcStruct), p => MapStruct((XRpcStruct)p.Value) },
{ typeof(XRpcArray), p => MapArray((XRpcArray)p.Value) },
};
}
/// <summary>
/// Maps a method response to XML.
/// </summary>
/// <param name="rpcMethodResponse">The method response to be mapped.</param>
/// <returns>The XML element.</returns>
public XElement MapMethodResponse(XRpcMethodResponse rpcMethodResponse) {
Argument.ThrowIfNull(rpcMethodResponse, "rpcMethodResponse");
return new XElement(
"methodResponse",
new XElement(
"params",
source.Params.Select(
rpcMethodResponse.Params.Select(
p => new XElement("param", MapValue(p)))));
}
XElement IMapper<XRpcData, XElement>.Map(XRpcData source) {
return new XElement("param", MapValue(source));
/// <summary>
/// Maps rpc data to XML.
/// </summary>
/// <param name="rpcData">The rpc data.</param>
/// <returns>The XML element.</returns>
public XElement MapData(XRpcData rpcData) {
Argument.ThrowIfNull(rpcData, "rpcData");
return new XElement("param", MapValue(rpcData));
}
XElement IMapper<XRpcStruct, XElement>.Map(XRpcStruct source) {
/// <summary>
/// Maps a rpc struct to XML.
/// </summary>
/// <param name="rpcStruct">The rpc struct.</param>
/// <returns>The XML element.</returns>
public XElement MapStruct(XRpcStruct rpcStruct) {
return new XElement(
"struct",
source.Members.Select(
rpcStruct.Members.Select(
kv => new XElement(
"member",
new XElement("name", kv.Key),
MapValue(kv.Value))));
}
XElement IMapper<XRpcArray, XElement>.Map(XRpcArray source) {
/// <summary>
/// Maps a rpc array to XML.
/// </summary>
/// <param name="rpcArray">The rpc array.</param>
/// <returns>The XML element.</returns>
public XElement MapArray(XRpcArray rpcArray) {
return new XElement(
"array",
new XElement(
"data",
source.Data.Select(d => MapValue(d))));
rpcArray.Data.Select(MapValue)));
}
XElement Map<T>(T t) {
return ((IMapper<T, XElement>)this).Map(t);
/// <summary>
/// Maps rpc data to XML.
/// </summary>
/// <param name="rpcData">The rpc data.</param>
/// <returns>The XML element.</returns>
private XElement MapValue(XRpcData rpcData) {
return new XElement("value", _dispatch[rpcData.Type](rpcData));
}
private XElement MapValue(XRpcData data) {
return new XElement("value", _dispatch[data.Type](data));
}
}
}
}
}