基于属性的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 语句并根据数据的外观构造 SponsorA
或 SponsorB
。其中任何一个都是 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 的正常许可。
我正在使用客户端调用 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 语句并根据数据的外观构造 SponsorA
或 SponsorB
。其中任何一个都是 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 的正常许可。