Переключение структуры модели данных на основе свойства c # - PullRequest
0 голосов
/ 15 ноября 2018

Я использую клиент для вызова API. В API - я хочу, чтобы модель заполнялась из тела запроса, - но я хочу, чтобы модель была структурирована по-разному в зависимости от имени одного свойства. По сути, я хочу создать что-то вроде сценария «переключение / случай» с моделью данных, но не уверен, как это реализовать. Последняя модель содержит псевдокод, основанный на том, что я хочу достичь (очевидно, универсальный тип не будет работать так, как я описал, но я чувствую, что он завершает мой пример). Вот мой пример:

Контроллер:

[HttpPost("customer", Name = "Submit Customer")]
public IActionResult ActivateCustomer([FromBody]Customer customer)
{
    //Do something with the Customer object.
    return Ok();
}

Модель клиента:

public class Customer
 {
     public CustomerInfo customerInfo { get; set; }
     public SponserInfo sponserInfo { get; set; }
 }

CustomerInfo:

public class CustomerInfo
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }

    //etc.
}

SponserA:

public class SponserA
{
    public int ReferenceId { get; set; }
    public string Password { get; set; }
}

SponserB:

public class SponserB
{
    public string UserName{ get; set; }
    public string Relation { get; set; }
    public string Department { get; set; }
}

SponserInfo: (псевдокод того, что я хотел бы)

public class SponserInfo
{
    public string SponserName { get; set; }
    public T SponserInfo { get; set; }

    switch(this.SponserName)
    {
        case "Sponser A's Name":
            T = SponserA;
            break;
        case "Sponser B's Name":
            T = SponserB;
            break;
    }
}

Ответы [ 3 ]

0 голосов
/ 16 ноября 2018

Примерно так:

public abstract class SponsorInfo
{
    public string SponserName { get; set; }

    protected SponsorInfo(string sponserName)
    {
        SponserName = sponserName;
    }
}

public class SponsorA : SponsorInfo
{
    public int ReferenceId { get; set; }
    public string Password { get; set; }

    public SponsorA(string sponserName, int referenceId, string password) 
        : base(sponserName)
    {
        ReferenceId = referenceId;
        Password = password;
    }
}

public class SponsorB : SponsorInfo
{
    public string UserName { get; set; }
    public string Relation { get; set; }
    public string Department { get; set; }

    public SponsorB(string sponsorName, string userName, string relation, string department) 
        : base(sponsorName)
    {
        UserName = userName;
        Relation = relation;
        Department = department;
    }
}

Затем оставьте свой класс Customer в покое (но исправьте опечатку):

public class Customer
{
    public CustomerInfo customerInfo { get; set; }
    public SponsorInfo sponsorInfo { get; set; }
}

и в контроллере добавьте оператор switchи создайте либо SponsorA, либо SponsorB в зависимости от того, как выглядят данные.Любой из них является SponsorInfo, поэтому вы можете прикрепить его как sponsorInfo в вашем Customer объекте.

0 голосов
/ 16 ноября 2018

Вот один расширяемый способ.

Атрибут отображает имя спонсора в подкласс, поэтому SponsorInfo не обязательно должен знать обо всех подклассах.

Он использует абстрактный базовый класс (Sponsor) для всех типов спонсоров (также рекомендуется @ Flydog57).

Когда назначено SponsorInfo.SponsorName, создается экземпляр его подкласса (поэтому сначала нужно назначить SponsorName).

Вы можете отрегулировать это в зависимости от того, как вы на самом деле отображаете свойства из вашей модели.

using System;
using System.Linq;
using System.Reflection;


/// <summary>
/// Attribute to indicate the name mapped to a <see cref="Sponsor"/> subclass.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class SponsorAttribute : Attribute
{
    public SponsorAttribute(string name)
    {
        this.Name = name;
    }

    /// <summary>
    /// The value that <see cref="SponserInfo.SponserName"/> must match for the attribute class to be used.
    /// </summary>
    public virtual string Name { get; set; }
}

public abstract class Sponsor
{
    public int ReferenceId { get; set; }
    public string Password { get; set; }
}

[Sponsor("Sponser A's Name")]
public class SponsorA : Sponsor
{
}

[Sponsor("Sponser B's Name")]
public class SponsorB : Sponsor
{
    public string Department { get; set; }
}

// More subclasses can be added.

public class SponsorInfo
{
    /// <summary>
    /// The Sponsor name.
    /// Changing this sets <see cref="Sponsor"/> to a new instance of the corresponding class.
    /// </summary>
    public string SponsorName
    {
        get { return _sponsorName; }
        set
        {
            if (_sponsorName != value)
            {
                _sponsorName = value;

                // Find a Sponsor subclass with a SponsorAttribute.Name matching the given value:
                Type sponsorType = Assembly.GetExecutingAssembly().GetTypes()   // you might want to also scan other assemblies
                    .Where(t =>
                        t.IsSubclassOf(typeof(Sponsor))
                        && (t.GetCustomAttribute<SponsorAttribute>()?.Name?.Equals(_sponsorName) ?? false)
                    ).FirstOrDefault();   // null if none is found

                if (sponsorType == null)
                    Sponsor = null;     // no matching class
                else
                    Sponsor = (Sponsor)Activator.CreateInstance(sponsorType);  // new instance of the matching class
            }
        }
    }
    private string _sponsorName;

    public Sponsor Sponsor { get; set; }   // renamed from "SponsorInfo" because that's the name of this class
}


Это двойная лицензия в качестве общественного достояния (CC0) и обычная лицензияПереполнение стека.
0 голосов
/ 15 ноября 2018

Почему бы не создать модель с именем Sponsor, в которой есть все ваши поля, а затем, если ReferenceId равно нулю, вы будете знать, какой это тип спонсора?

public class SponsorInfo 
{
    public int? ReferenceId { get; set; }
    public string Password { get; set; }
    public string UserName { get; set; }
    public string Relation { get; set; }
    public string Department { get; set; }
}

[HttpPost("customer", Name = "Submit Customer")]
public IActionResult ActivateCustomer([FromBody]Customer customer)
{
    //Do something with the Customer object.
    if (customer.sponsorInfo.ReferenceId == null || !customer.sponsorInfo.ReferenceId.HasValue)
    {
        //is SponsorB
    }
    else
    {
        //is SponsorA
    }
    return Ok();
}
...