基于属性的switch数据模型结构c#

Switch data model structure based upon property c#

我正在使用客户端调用 API。在 API 中——我希望模型从请求主体中填充——但我希望模型的结构根据单个 属性 的名称而不同。基本上我想用数据模型创建类似 switch/case 的场景,但我不确定如何实现它。最后一个模型包含基于我想要实现的目标的伪代码(显然泛型类型不会按照我描述的方式工作,但我觉得它完成了我的示例)。这是我的例子:

控制器:

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

客户信息:

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

    //etc.
}

赞助商A:

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

赞助商B:

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

为什么不创建一个名为 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();
}

这样的事情怎么样:

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

然后,让您的客户 class 独自一人(但请修正错字):

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

然后在您的控制器中,添加 switch 语句并根据数据的外观构造 SponsorASponsorB。其中任何一个都是 SponsorInfo,因此您可以将其作为 sponsorInfo 附加到 Customer 对象中。

这是一种可扩展的方式。

属性将赞助商名称映射到子class,因此 SponsorInfo 不必知道所有子classes。

它对所有赞助商类型使用抽象基础 class (Sponsor)(@Flydog57 也推荐)。

SponsorInfo.SponsorName赋值时,会创建一个子实例class(所以你必须先赋值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
}


这是双重许可的 public 域 (CC0) 和 Stack Overflow 的正常许可。