Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.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# 有没有比手工检查每个属性更有效的合并模型的方法?_C# - Fatal编程技术网

C# 有没有比手工检查每个属性更有效的合并模型的方法?

C# 有没有比手工检查每个属性更有效的合并模型的方法?,c#,C#,我正在构建一个API,在这个API中,如果调用方在HTTP调用的主体中包含了某些属性,我只想发送这些属性的更新 我目前正在做以下工作。。但它看起来很笨重。有没有更简单的方法 public void MergePerson(Person basePerson, Person updatedPerson) { if (updatedPerson.Title != null) basePerson.Title = updatedPerson.Ti

我正在构建一个API,在这个API中,如果调用方在HTTP调用的主体中包含了某些属性,我只想发送这些属性的更新

我目前正在做以下工作。。但它看起来很笨重。有没有更简单的方法

    public void MergePerson(Person basePerson, Person updatedPerson)
    {
        if (updatedPerson.Title != null)
            basePerson.Title = updatedPerson.Title;

        if (updatedPerson.Initials != null)
            basePerson.Initials = updatedPerson.Initials;

        if (updatedPerson.FirstName != null)
            basePerson.FirstName = updatedPerson.FirstName;

        if (updatedPerson.LastName != null)
            basePerson.LastName = updatedPerson.LastName;

        if (updatedPerson.Sex != null)
            basePerson.Sex = updatedPerson.Sex;

        if (updatedPerson.DateOfBirth != null)
            basePerson.DateOfBirth = updatedPerson.DateOfBirth;

        if (updatedPerson.JobTitle != null)
            basePerson.JobTitle = updatedPerson.JobTitle;

        <<< snip >>>
public void MergePerson(Person-basePerson,Person-updatedPerson)
{
if(updatedPerson.Title!=null)
basePerson.Title=updatedPerson.Title;
if(updatedPerson.Initials!=null)
basePerson.Initials=updatedPerson.Initials;
if(updatedPerson.FirstName!=null)
basePerson.FirstName=updatedPerson.FirstName;
if(updatedPerson.LastName!=null)
basePerson.LastName=updatedPerson.LastName;
if(updatedPerson.Sex!=null)
basePerson.Sex=更新的Person.Sex;
if(updatedPerson.DateOfBirth!=null)
basePerson.DateOfBirth=updatedPerson.DateOfBirth;
if(updatedPerson.JobTitle!=null)
basePerson.JobTitle=updatedPerson.JobTitle;
>
由于这个原因,我不得不将bools设置为non-nullable,这样我就可以确认它们实际上是被传递的,而不是仅仅设置为默认值false


我担心的是,有一天我会向模型中添加新字段,而忘了在此处添加它们。

您要做的是称为补丁

检查此代码

public class Car 
{

    public int Id { get; set; }

    [Required]
    [StringLength(20)]
    public string Make { get; set; }

    [Required]
    [StringLength(20)]
    public string Model { get; set; }

    public int Year { get; set; }

    [Range(0, 500000)]
    public float Price { get; set; }
}

public class CarPatch
{
    [StringLength(20)]
    public string Make { get; set; }

    [StringLength(20)]
    public string Model { get; set; }

    public int? Year { get; set; }

    [Range(0, 500000)]
    public float? Price { get; set; }
}   

public class CarsController : ApiController
{
    private readonly CarsContext _carsCtx = new CarsContext();

    // PATCH /api/cars/{id}
    public Car PatchCar(int id, CarPatch car)
    {
    var carTuple = _carsCtx.GetSingle(id);
    if (!carTuple.Item1)
    {
        var response = Request.CreateResponse(HttpStatusCode.NotFound);
        throw new HttpResponseException(response);
    }

    Patch<CarPatch, Car>(car, carTuple.Item2);

    // Not required but better to put here to simulate the external storage.
    if (!_carsCtx.TryUpdate(carTuple.Item2))
    {
        var response = Request.CreateResponse(HttpStatusCode.NotFound);
        throw new HttpResponseException(response);
    }

    return carTuple.Item2;
}

// private helpers
private static ConcurrentDictionary<Type, PropertyInfo[]> TypePropertiesCache = 
    new ConcurrentDictionary<Type, PropertyInfo[]>();

private void Patch<TPatch, TEntity>(TPatch patch, TEntity entity)
    where TPatch : class
    where TEntity : class
{
    PropertyInfo[] properties = TypePropertiesCache.GetOrAdd(
        patch.GetType(), 
        (type) => type.GetProperties(BindingFlags.Instance | BindingFlags.Public));

    foreach (PropertyInfo prop in properties)
    {
        PropertyInfo orjProp = entity.GetType().GetProperty(prop.Name);
        object value = prop.GetValue(patch);
        if (value != null)
        {
            orjProp.SetValue(entity, value);
        }
    }
}
}
公车
{
公共int Id{get;set;}
[必需]
[行政长官(20)]
公共字符串Make{get;set;}
[必需]
[行政长官(20)]
公共字符串模型{get;set;}
公共整数年{get;set;}
[范围(0,500000)]
公开浮动价格{get;set;}
}
公共级停车场
{
[行政长官(20)]
公共字符串Make{get;set;}
[行政长官(20)]
公共字符串模型{get;set;}
公共整数?年份{get;set;}
[范围(0,500000)]
公开浮动?价格{get;set;}
}   
公共类车辆控制器:ApiController
{
私有只读CarsContext_carsCtx=new CarsContext();
//补丁/api/cars/{id}
公共汽车修补车(内部id,汽车修补车)
{
var carTuple=\u carsCtx.GetSingle(id);
如果(!carTuple.Item1)
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
补丁(car,carTuple.Item2);
//不需要,但最好放在这里模拟外部存储。
如果(!\u carsCtx.TryUpdate(carTuple.Item2))
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
返回carTuple.Item2;
}
//私人佣工
私有静态ConcurrentDictionary类型属性缓存=
新的ConcurrentDictionary();
专用无效补丁(TPatch补丁、TEntity实体)
TPatch的位置:类
地点:班级
{
PropertyInfo[]properties=TypePropertiesCache.GetOrAdd(
patch.GetType(),
(type)=>type.GetProperties(BindingFlags.Instance | BindingFlags.Public));
foreach(PropertyInfo属性中的属性)
{
PropertyInfo或jprop=entity.GetType().GetProperty(prop.Name);
对象值=prop.GetValue(面片);
if(值!=null)
{
orjProp.SetValue(实体,值);
}
}
}
}

您要做的是称为补丁

检查此代码

public class Car 
{

    public int Id { get; set; }

    [Required]
    [StringLength(20)]
    public string Make { get; set; }

    [Required]
    [StringLength(20)]
    public string Model { get; set; }

    public int Year { get; set; }

    [Range(0, 500000)]
    public float Price { get; set; }
}

public class CarPatch
{
    [StringLength(20)]
    public string Make { get; set; }

    [StringLength(20)]
    public string Model { get; set; }

    public int? Year { get; set; }

    [Range(0, 500000)]
    public float? Price { get; set; }
}   

public class CarsController : ApiController
{
    private readonly CarsContext _carsCtx = new CarsContext();

    // PATCH /api/cars/{id}
    public Car PatchCar(int id, CarPatch car)
    {
    var carTuple = _carsCtx.GetSingle(id);
    if (!carTuple.Item1)
    {
        var response = Request.CreateResponse(HttpStatusCode.NotFound);
        throw new HttpResponseException(response);
    }

    Patch<CarPatch, Car>(car, carTuple.Item2);

    // Not required but better to put here to simulate the external storage.
    if (!_carsCtx.TryUpdate(carTuple.Item2))
    {
        var response = Request.CreateResponse(HttpStatusCode.NotFound);
        throw new HttpResponseException(response);
    }

    return carTuple.Item2;
}

// private helpers
private static ConcurrentDictionary<Type, PropertyInfo[]> TypePropertiesCache = 
    new ConcurrentDictionary<Type, PropertyInfo[]>();

private void Patch<TPatch, TEntity>(TPatch patch, TEntity entity)
    where TPatch : class
    where TEntity : class
{
    PropertyInfo[] properties = TypePropertiesCache.GetOrAdd(
        patch.GetType(), 
        (type) => type.GetProperties(BindingFlags.Instance | BindingFlags.Public));

    foreach (PropertyInfo prop in properties)
    {
        PropertyInfo orjProp = entity.GetType().GetProperty(prop.Name);
        object value = prop.GetValue(patch);
        if (value != null)
        {
            orjProp.SetValue(entity, value);
        }
    }
}
}
公车
{
公共int Id{get;set;}
[必需]
[行政长官(20)]
公共字符串Make{get;set;}
[必需]
[行政长官(20)]
公共字符串模型{get;set;}
公共整数年{get;set;}
[范围(0,500000)]
公开浮动价格{get;set;}
}
公共级停车场
{
[行政长官(20)]
公共字符串Make{get;set;}
[行政长官(20)]
公共字符串模型{get;set;}
公共整数?年份{get;set;}
[范围(0,500000)]
公开浮动?价格{get;set;}
}   
公共类车辆控制器:ApiController
{
私有只读CarsContext_carsCtx=new CarsContext();
//补丁/api/cars/{id}
公共汽车修补车(内部id,汽车修补车)
{
var carTuple=\u carsCtx.GetSingle(id);
如果(!carTuple.Item1)
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
补丁(car,carTuple.Item2);
//不需要,但最好放在这里模拟外部存储。
如果(!\u carsCtx.TryUpdate(carTuple.Item2))
{
var response=Request.CreateResponse(HttpStatusCode.NotFound);
抛出新的HttpResponseException(响应);
}
返回carTuple.Item2;
}
//私人佣工
私有静态ConcurrentDictionary类型属性缓存=
新的ConcurrentDictionary();
专用无效补丁(TPatch补丁、TEntity实体)
TPatch的位置:类
地点:班级
{
PropertyInfo[]properties=TypePropertiesCache.GetOrAdd(
patch.GetType(),
(type)=>type.GetProperties(BindingFlags.Instance | BindingFlags.Public));
foreach(PropertyInfo属性中的属性)
{
PropertyInfo或jprop=entity.GetType().GetProperty(prop.Name);
对象值=prop.GetValue(面片);
if(值!=null)
{
orjProp.SetValue(实体,值);
}
}
}
}

通过反射,您可以轻松做到这一点:

public static void MapPersons(object basePerson, object updatedPerson)
{
    var sourceT = basePerson.GetType();
    var sourceProps = sourceT.GetProperties();

    var targetT = updatedPerson.GetType();
    var targetProps = targetT.GetProperties();

    foreach (var sProp in sourceProps)
    {
        var sourceValue = sProp.GetValue(basePerson, null);
        var propIndex = Array.IndexOf(targetProps, sProp);
        if (propIndex != -1)
        {
            var tProp = targetProps[propIndex];
            tProp.SetValue(updatedPerson, sourceValue);
        }
    }
}

但这里有很多功能强大的工具,例如。它们将为您处理这些问题。

您可以通过反射轻松实现这一点:

public static void MapPersons(object basePerson, object updatedPerson)
{
    var sourceT = basePerson.GetType();
    var sourceProps = sourceT.GetProperties();

    var targetT = updatedPerson.GetType();
    var targetProps = targetT.GetProperties();

    foreach (var sProp in sourceProps)
    {
        var sourceValue = sProp.GetValue(basePerson, null);
        var propIndex = Array.IndexOf(targetProps, sProp);
        if (propIndex != -1)
        {
            var tProp = targetProps[propIndex];
            tProp.SetValue(updatedPerson, sourceValue);
        }
    }
}

但是这里有很多功能强大的工具,比如。它们会为您处理这些问题。

不知道更简单,但是一行应该是
basePerson.Title=updatedPerson.Title!=null?updatedPerson.Title:“否则”
等等(用您想要的默认值替换为“否则”)。谢谢..但我不想要“否则”第……Y节