C# 如何重新构建模型类型以减少代码复制

C# 如何重新构建模型类型以减少代码复制,c#,inheritance,C#,Inheritance,我有3种型号: public class BankA_Transaction : BanKTransactionMetaData { public string GROUPName { get; set; } public string ACC_ID { get; set; } public string ACCOUNT_NO { get; set; } } public class BankB_Transaction : BanKTransactionMetaDat

我有3种型号:

public class BankA_Transaction : BanKTransactionMetaData
{
    public string GROUPName { get; set; }
    public string ACC_ID { get; set; }
    public string ACCOUNT_NO { get; set; }
}


public class BankB_Transaction : BanKTransactionMetaData
{
    public string Name { get; set; }
    public string ACC_ID { get; set; }
    public string ACCOUNT_NO { get; set; }
}

public class BankC_Transaction : BanKTransactionMetaData
{
    public string FullName { get; set; }
    public string ACC_ID { get; set; }
    public string ACCOUNT_NO { get; set; }
}
注意:实际的属性列表要长得多

所有这些都继承了保存到数据库时所需的一些字段

public class BanKTransactionMetaData
{
    public String BankName { get; set; } 
}
public void SaveBankA(BankA bankA)
{
      bankA.BankName = "Bank_A";
      string jsonText = JsonConvert.SerializeObject(bankA_Transaction, Formatting.Indented);

Code for saving...
这些模型由银行发送的文件中的记录填充,然后保存到数据库中。 作为此保存的一部分,我将记录转换为数据库所需的JSON

public class BanKTransactionMetaData
{
    public String BankName { get; set; } 
}
public void SaveBankA(BankA bankA)
{
      bankA.BankName = "Bank_A";
      string jsonText = JsonConvert.SerializeObject(bankA_Transaction, Formatting.Indented);

Code for saving...
目前我对储蓄银行a、储蓄银行a和储蓄银行B有不同的方法

在我看来,这是代码复制,我应该让所有模型更好地继承,以便使用基类型?而不是每个命名类型

我读过抽象类和虚拟类,因为我怀疑这正是我需要的,但我不知道如何将它们连接在一起

我不能只在SaveBankA中使用Object,因为我需要添加.BankName


是否有更好的架构来减少代码复制?

也许您需要这样的架构

在基本服务类中:

protected void SaveBankTransaction(BankTransactionMetaData tran)
{
    string jsonText = JsonConvert.SerializeObject(tran, Formatting.Indented);
    // additional saving code
}
在儿童服务班:

public void SaveBankA(BankA bankA)
{
    bankA.BankName = "Bank_A";
    base.SaveBankTransaction(bankA);
}

也许你需要这样的东西

在基本服务类中:

protected void SaveBankTransaction(BankTransactionMetaData tran)
{
    string jsonText = JsonConvert.SerializeObject(tran, Formatting.Indented);
    // additional saving code
}
在儿童服务班:

public void SaveBankA(BankA bankA)
{
    bankA.BankName = "Bank_A";
    base.SaveBankTransaction(bankA);
}

创建两个接口,一个用于元数据(
IBankData
),另一个用于银行交易详细信息(
IBankTransaction
)。
IBankData
界面将维护对
IBankTransaction
界面的引用。这还应允许您在需要时添加其他银行,例如银行D

public interface IBankData
{
    string BankName { get; }
    // ... additional bank meta data properties
    // ...
    IBankTransaction Transaction { get; set; }
}

public interface IBankTransaction
{
    [JsonProperty("ACC_ID")]
    string AccountId { get; set; }
    [JsonProperty("ACCOUNT_NO")]
    string AccountNumber { get; set; }
    // ... additional shared bank transaction properties
    // ...
}
仅供参考,我选择使用
JsonProperty
属性来控制JSON键的名称,这允许根据最佳实践命名类属性,而不影响JSON属性名称

接下来,为您将要使用的每个银行实现接口。在每个银行中添加仅适用于每个实现的附加属性,即由于
GroupName
属性仅由
BankA
使用,因此此属性将添加到
BankA
类中,而不是接口中。这同样适用于任何其他特定于银行的房地产

银行A

public class BankA : IBankData
{
    public string BankName => "BankA";
    public IBankTransaction Transaction { get; set; }
}

public class BankATransaction : IBankTransaction
{
    // Bank A specific properties
    [JsonProperty("GROUPName")]
    public string GroupName { get; set; }
    // ... additional Bank A specific properties
    // ...

    // interface implemented properties
    public string AccountId { get; set; }
    public string AccountNumber { get; set; }
}
银行B

public class BankB : IBankData
{
    public string BankName => "BankB";
    public IBankTransaction Transaction { get; set; }
}

public class BankBTransaction : IBankTransaction
{
    // Bank B specific properties
    public string Name { get; set; }
    // ... additional Bank B specific properties
    // ...

    // interface implemented properties
    public string AccountId { get; set; }
    public string AccountNumber { get; set; }        
}
银行C

public class BankC : IBankData
{
    public string BankName => "BankC";
    public IBankTransaction Transaction { get; set; }
}

public class BankCTransaction : IBankTransaction
{
    // Bank B specific properties
    public string FullName { get; set; }
    // ... additional Bank B specific properties
    // ...

    // interface implemented properties
    public string AccountId { get; set; }
    public string AccountNumber { get; set; }
}
JsonConverter

由于
IBankTransaction
IBankData
中的一个属性,因此这将更改JSON结构。您可能不希望这样做,为了保留您的结构,可以在
IBankData
接口上实现
JsonConverter
。这将删除JSON中的事务对象,并将子属性移动到JSON根目录下

public class BankJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        JToken t = JToken.FromObject(value);
        if (t.Type != JTokenType.Object)
        {
            t.WriteTo(writer);
        }
        else
        {
            JObject o = (JObject)t;
            JProperty transactionProperty = o.Properties().FirstOrDefault(p => p.Name == "Transaction");
            o.Remove("Transaction");
            JToken token = transactionProperty;
            foreach (JToken ct in token.Children())
            {
                foreach (var prop in JProperty.FromObject(ct))
                {
                    o.Add(prop);
                }
            }
            serializer.Serialize(writer, o);
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }
    public override bool CanRead => false;
    public override bool CanConvert(Type objectType)
    {
         return objectType.GetInterfaces().Contains(typeof(IBankData));
    }
} 
用法

对于使用示例,我创建了一些测试函数来准备数据,并添加了
SaveBank
方法,您可以在实际代码中重新定位,因为这对您的解决方案很有意义

class Program
{
    static void Main(string[] args)
    {            
        string bankATransJson = GetBankATestJsonInput();
        BankATransaction bankATransaction = JsonConvert.DeserializeObject<BankATransaction>(bankATransJson);
        BankA bankA = new BankA();
        bankA.Transaction = bankATransaction;
        Console.WriteLine(SaveBank(bankA));
        // output:
        // {
        // "BankName": "BankA",
        // "GROUPName": "g54321",
        // "ACC_ID": "A01",
        // "ACCOUNT_NO": "A1111"
        // }

        string bankBInputJson = GetBankBTestJsonInput();
        BankBTransaction bankBTransInput = JsonConvert.DeserializeObject<BankBTransaction>(bankBInputJson);
        BankB bankB = new BankB();
        bankB.Transaction = bankBTransInput;
        Console.WriteLine(SaveBank(bankB));
       // output:
       // {
       // "BankName": "BankB",
       // "ACC_ID": "B02",
       // "ACCOUNT_NO": "B2222",
       // "Name": "Bank_Of_B           
       // }

        string bankCInputJson = GetBankCTestJsonInput();
        BankCTransaction bankCTransInput = JsonConvert.DeserializeObject<BankCTransaction>(bankCInputJson);
        BankC bankC = new BankC();
        bankC.Transaction = bankCTransInput;
        Console.WriteLine(SaveBank(bankC));
        // output:
        // {
        // "BankName": "BankC",
        // "ACC_ID": "C03",
        // "ACCOUNT_NO": "C3333",
        // "FullName": "C Bank"
        // }
    }

    public static string SaveBank(IBankData bankData)
    {
        // when calling the serialize object method, we pass our BankJsonConverter
        string jsonText = JsonConvert.SerializeObject(bankData, Formatting.Indented, new BankJsonConverter());
        // this example just returns the JSON text
        // but you would implement your save logic as needed
        return jsonText;
    }

    private static string GetBankATestJsonInput()
    {
        var obj = new { ACC_ID = "A01", ACCOUNT_NO = "A1111", GROUPName = "g54321" };
        return JsonConvert.SerializeObject(obj);
    }

    private static string GetBankBTestJsonInput()
    {
        var obj = new { ACC_ID = "B02", ACCOUNT_NO = "B2222", Name = "Bank_Of_B" };
        return JsonConvert.SerializeObject(obj);
    }

    private static string GetBankCTestJsonInput()
    {
        var obj = new { ACC_ID = "C03", ACCOUNT_NO = "C3333", FullName = "C Bank" };
        return JsonConvert.SerializeObject(obj);
    }
}
类程序
{
静态void Main(字符串[]参数)
{            
字符串bankATransJson=GetBankATestJsonInput();
BankATransaction BankATransaction=JsonConvert.DeserializeObject(bankATransJson);
BankA BankA=新BankA();
bankA.Transaction=bankATransaction;
控制台写入线(储蓄银行(bankA));
//输出:
// {
//“银行名称”:“银行”,
//“组名”:“g54321”,
//“ACC_ID”:“A01”,
//“账号”:“A1111”
// }
字符串bankBInputJson=GetBankBTestJsonInput();
BankBTransaction bankBTransInput=JsonConvert.DeserializeObject(bankBInputJson);
BankB BankB=新的BankB();
bankB.Transaction=bankBTransInput;
控制台写入线(储蓄银行(bankB));
//输出:
// {
//“银行名称”:“银行B”,
//“附件ID”:“B02”,
//“账号”:“B2222”,
//“名称”:“B银行”
// }
字符串bankCInputJson=GetBankCTestJsonInput();
BankCtTransaction BankCtTransInput=JsonConvert.DeserializeObject(bankCInputJson);
BankC BankC=新BankC();
bankC.Transaction=bankCTransInput;
控制台写入线(储蓄银行(bankC));
//输出:
// {
//“银行名称”:“BankC”,
//“附件ID”:“C03”,
//“账号”:“C3333”,
//“全名”:“C银行”
// }
}
公共静态字符串存储库(IBankData bankData)
{
//调用serialize对象方法时,我们传递BankJsonConverter
string jsonText=JsonConvert.SerializeObject(bankData,Formatting.Indented,new BankJsonConverter());
//本例仅返回JSON文本
//但您可以根据需要实现save逻辑
返回jsonText;
}
私有静态字符串GetBankATestJsonInput()
{
var obj=new{ACC_ID=“A01”,ACCOUNT_NO=“A1111”,GROUPName=“g54321”};
返回JsonConvert.SerializeObject(obj);
}
私有静态字符串GetBankBTestJsonInput()
{
var obj=new{ACC_ID=“B02”,ACCOUNT_NO=“B2222”,Name=“Bank_Of_B”};
返回JsonConvert.SerializeObject(obj);
}
私有静态字符串GetBankCTestJsonInput()
{
var obj=new{ACC_ID=“C03”,ACCOUNT_NO=“c333”,FullName=“C Bank”};
返回JsonConvert.SerializeObject(obj);
}
}

创建两个接口,一个用于元数据(
IBankData
),另一个用于银行交易详细信息(
IBankTransaction
).
IBankData
界面将维护对
IBankTransaction
界面的引用。这还应允许您在需要时添加其他银行,例如银行D

public interface IBankData
{
    string BankName { get; }
    // ... additional bank meta data properties
    // ...
    IBankTransaction Transaction { get; set; }
}

public interface IBankTransaction
{
    [JsonProperty("ACC_ID")]
    string AccountId { get; set; }
    [JsonProperty("ACCOUNT_NO")]
    string AccountNumber { get; set; }
    // ... additional shared bank transaction properties
    // ...
}
仅供参考,我选择使用
JsonProperty
属性来控制JSON键的名称,这允许根据最佳实践命名类属性,而不影响JSON属性名称

接下来,为您将要使用的每个银行实现接口。在每个银行中添加仅适用于每个实现的附加属性,即自