Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.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
C# 将一层POCO转换为另一层POCO的设计问题_C#_Architecture - Fatal编程技术网

C# 将一层POCO转换为另一层POCO的设计问题

C# 将一层POCO转换为另一层POCO的设计问题,c#,architecture,C#,Architecture,我在WCF服务应用程序中有一层业务级对象和一层合同级对象。我所指的业务层对象只是我用来保存数据的实体或POCO对象。我所指的契约级对象是构成我的客户机所看到的WSDL(也是POCO)的对象 当我将数据从WCF服务返回给客户机时,请求参数将从一个或多个合同层对象中水合为XML,并转发到服务器上 我试图创建一个位于契约和业务层之外的类,该类将对象从一个层转换到另一个层。例如,在合同层中,我有一个类,如: public class Person { public string Name { g

我在WCF服务应用程序中有一层业务级对象和一层合同级对象。我所指的业务层对象只是我用来保存数据的实体或POCO对象。我所指的契约级对象是构成我的客户机所看到的WSDL(也是POCO)的对象

当我将数据从WCF服务返回给客户机时,请求参数将从一个或多个合同层对象中水合为XML,并转发到服务器上

我试图创建一个位于契约和业务层之外的类,该类将对象从一个层转换到另一个层。例如,在合同层中,我有一个类,如:

public class Person
{
    public string Name { get; set;};
}
我还可以在业务层中有一个相同的类(也可以不同),其属性将映射到此类中的属性

然后我有一个类,它执行如下代码:

public Contract.Person TranslatePerson(Business.Person person)
{
    Contract.Person result = new Contract.Person();
    result.Name = person.Name;
    return result;
}
// remains for backwards compatibility for V1 clients
namespace Contract.V1
{
    public class Person
    {
        public string Name { get; set;};
    }
}

namespace Contract.V2
{
    public class Person
    {
        public string FirstName { get; set;};
        public string LastName { get; set;};
    }
}
这一切都按预期进行。但是,此转换器服务的一个要求是将业务层与契约层中的更改隔离开来,并且此层的一个要求是允许契约层的不同版本同时存在,以支持SOAP客户端的向后兼容性。例如,如果在服务的v2中,我想将lastname添加到person类中,并将name更改为FirstName,以便我的SOAP客户机现在可以看到这两个数据点,我将有如下内容:

public Contract.Person TranslatePerson(Business.Person person)
{
    Contract.Person result = new Contract.Person();
    result.Name = person.Name;
    return result;
}
// remains for backwards compatibility for V1 clients
namespace Contract.V1
{
    public class Person
    {
        public string Name { get; set;};
    }
}

namespace Contract.V2
{
    public class Person
    {
        public string FirstName { get; set;};
        public string LastName { get; set;};
    }
}
现在,当我需要将V2 Person发送回客户机时,我希望将业务对象中的FirstName映射到FirstName,将LastName映射到LastName。然而,如果我需要发回一个V1用户,我会将FirstName映射到Name,只需删除LastName

因此,我为翻译层创建的架构是:

public class V1Translator
{
    public virtual Contract.V1.Person TranslatePerson(Business.Person person)
    {
        Contract.V1.Person result = new Contract.V1.Person();
        result.Name = person.Name;
        return result;
    }
}

public class V2Translator : V1Translator
{
    public override Contract.V2.Person TranslatePerson(Business.Person person)
    {
        Contract.V2.Person result = new Contract.V2.Person();
        result.Name = person.Name;
        return result;
    }
}
这为我节省了很多时间,因为我在V1Translator中可能有100种不同的翻译方法,但我可能只需要在V2Translator中重写2或3,因为在不同的层中可能只有少数对象发生更改。我还使用工厂实例化了相应的Translator类。通过这种方式,我可以在我的特殊TranslationService类上调用TranslationPerson,让它确定使用哪个翻译器。然而,这也是问题所在。我无法重写基类中的方法,因为返回类型不同。尽管它们都是契约人对象,但它们位于不同的名称空间中。我很难通过这个考试

有人能帮我想出一个解决这个问题的好办法吗


感谢您查看,它在减少您在这种情况下需要编写的手动映射代码方面非常出色。

我编写了这两种扩展方法来解决这个问题,它们可能会为您解决问题提供一个良好的起点

public static Y To<X, Y>(this X source) where X : IActiveRecord where Y: class
{
    try
    {
        Y target = Activator.CreateInstance(typeof(Y)) as Y;

        BindingFlags memberAccess = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.SetProperty;

        PropertyInfo[] targetProperties = target.GetType().GetProperties(memberAccess);
        foreach (MemberInfo Field in targetProperties)
        {
            string name = Field.Name;

            if (Field.MemberType == MemberTypes.Property)
            {
                PropertyInfo targetProperty = Field as PropertyInfo;
                PropertyInfo sourceProperty = source.GetType().GetProperty(name, memberAccess);

                if (sourceProperty == null) { continue; }

                if (targetProperty.CanWrite && sourceProperty.CanRead)
                {
                    object targetValue = targetProperty.GetValue(target, null);
                    object sourceValue = sourceProperty.GetValue(source, null);

                    if (sourceValue == null) { continue; }

                    if (targetProperty.PropertyType.FullName == sourceProperty.PropertyType.FullName)
                    {
                        object tempSourceValue = sourceProperty.GetValue(source, null);
                        targetProperty.SetValue(target, tempSourceValue, null);
                    }
                }
            }
        }

        return target;
    }
    // it's important to return null if there are any errors.
    catch { return null; }
}


public static IList<Y> To<X, Y>(this BindingListEx<X> collection) where X : IActiveRecord where Y : class
{
    IList<Y> returnList = new List<Y>();

    foreach (X item in collection)
        returnList.Add(item.To<X,Y>());

    return returnList;
}
公共静态Y到(此X源),其中X:IActiveRecord其中Y:class
{
尝试
{
Y target=Activator.CreateInstance(typeof(Y))作为Y;
BindingFlags memberAccess=BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.SetProperty;
PropertyInfo[]targetProperties=target.GetType().GetProperties(memberAccess);
foreach(targetProperties中的MemberInfo字段)
{
字符串名称=Field.name;
if(Field.MemberType==MemberTypes.Property)
{
PropertyInfo targetProperty=作为PropertyInfo的字段;
PropertyInfo sourceProperty=source.GetType().GetProperty(名称,memberAccess);
如果(sourceProperty==null){continue;}
if(targetProperty.CanWrite&&sourceProperty.CanRead)
{
object targetValue=targetProperty.GetValue(target,null);
object sourceValue=sourceProperty.GetValue(source,null);
如果(sourceValue==null){continue;}
if(targetProperty.PropertyType.FullName==sourceProperty.PropertyType.FullName)
{
对象tempSourceValue=sourceProperty.GetValue(源,空);
SetValue(target,tempSourceValue,null);
}
}
}
}
回报目标;
}
//如果有任何错误,返回null是很重要的。
catch{return null;}
}
公共静态IList到(此BindingListX集合),其中X:IActiveRecord其中Y:class
{
IList returnList=新列表();
foreach(集合中的X项)
returnList.Add(item.To());
退货清单;
}

我用它将亚音速2实体(因此是IActiveRecord约束)转换为我自己的POCO

,如果我昨天看到的话:(.看起来像我想要处理对象映射单调性的东西。