传递动态类型、迭代字段和替换值
本文关键字:字段 替换 迭代 动态 类型 | 更新日期: 2023-09-27 18:25:10
我有3/4个不同的模型,每个模型都包含自己的嵌套模型。我需要一种迭代所有字段的方法,包括嵌套模型的字段,并进行字符串替换(尽管并非所有字段都是字符串)。
我最初的想法是编写一个允许传递"动态"类型的方法。
输入型号:
Name = Joe
Surname = Smith
Address = new ClientAddress
{
Line1: Item A
Line2: mistake
Line3: mistake
}
我的示例方法:
MyMethod (dynamic passInModel)
{
....
passInModel.Replace("mistake","correction");
return passInModel;
}
输出:
Name = Joe
Surname = Smith
Address = new ClientAddress
{
Line1: Item A
Line2: correction
Line3: correction
}
尽管我尝试了各种方法,但我并没有成功地写出能胜任这项工作的东西。
您可以编写一个接受object
的方法,并使用反射来迭代所有字段,但在那里您会陷入混乱。在我看来,即使在这里使用dynamic
也是很混乱的。
考虑在此处使用修改后的访问者模式。如果你的域对象看起来像这样:
public class ModelBase
{
}
public class MyModel1 : ModelBase
{
public string Name { get; set; }
public string Surname { get; set; }
public ClientAddress Address { get; set; }
}
public class MyModel2 : ModelBase
{
public string CompanyName { get; set; }
public string Region { get; set; }
public CompanyAddress Address { get; set; }
}
public class ClientAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
}
public class CompanyAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public List<string> AdditionalLines { get; set; }
}
编写一个访问者,该访问者接受抽象ModelBase
并发送正确类型的安全访问者:
public class ModelFixVisitor
{
public ModelBase Visit(ModelBase model)
{
var asModel1 = model as MyModel1;
if (asModel1 != null)
{
return new Model1FixVisitor().Visit(asModel1);
}
var asModel2 = model as MyModel2;
if (asModel2 != null)
{
return new Model2FixVisitor().Visit(asModel2);
}
throw new NotImplementedException("Unknown model type.");
}
}
然后为您需要访问的每种类型(和子类型)编写一个简单的类:
public class Model1FixVisitor
{
public MyModel1 Visit(MyModel1 model)
{
model.Name = new StringFixVisitor().Visit(model.Name);
model.Surname = new StringFixVisitor().Visit(model.Surname);
model.Address = new ClientAddressFixVisitor().Visit(model.Address);
return model;
}
}
public class Model2FixVisitor
{
public MyModel2 Visit(MyModel2 model)
{
model.CompanyName = new StringFixVisitor().Visit(model.CompanyName);
model.Region = new StringFixVisitor().Visit(model.Region);
model.Address = new CompanyAddressFixVisitor().Visit(model.Address);
return model;
}
}
public class ClientAddressFixVisitor
{
public ClientAddress Visit(ClientAddress address)
{
address.Line1 = new StringFixVisitor().Visit(address.Line1);
address.Line2 = new StringFixVisitor().Visit(address.Line2);
address.Line3 = new StringFixVisitor().Visit(address.Line3);
return address;
}
}
public class CompanyAddressFixVisitor
{
public CompanyAddress Visit(CompanyAddress address)
{
address.Line1 = new StringFixVisitor().Visit(address.Line1);
address.Line2 = new StringFixVisitor().Visit(address.Line2);
address.AdditionalLines = new StringListFixVisitor().Visit(address.AdditionalLines);
return address;
}
}
public class StringFixVisitor
{
public string Visit(string element)
{
return element.Replace("mistake", "correction");
}
}
public class StringListFixVisitor
{
public List<string> Visit(List<string> elements)
{
return elements
.Select(x => new StringFixVisitor().Visit(x))
.ToList();
}
}
我确信代码可以重构和优化,但它应该表达总体思想。
我喜欢这种解决方案的地方在于,它将问题分解为可管理的小块:我如何修复string
?如何修复ClientAddress
?
然后,修复整个模型就变成了这些较小类的简单组合。这有点冗长,但您可以保持类型安全,不必干扰反射。
您可以使用.Net反射的功能来解决此问题。
我创建了一个名为DeepStringReplacer的类。使用反射,它遍历对象属性,如果类型是字符串,则执行字符串替换。
检查以下代码:
public class DeepStringReplacer
{
public object Replace(object input, string oldValue, string newValue)
{
if (input is string)
{
return input.ToString().Replace(oldValue, newValue);
}
var fields = input.GetType().GetProperties();
foreach (var field in fields)
{
var fieldValue = field.GetValue(input);
field.SetValue(input, Replace(fieldValue, oldValue, newValue));
}
return input;
}
}
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public ClientAddress Address { get; set; }
}
public class ClientAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
}