优化代码结构C#

Optimizing code structure C#

这是我编写的代码,用于在尝试更新数据库之前检查我的视图模型中的属性是否为空

   var channel = _context.Channels.FirstOrDefault(x => x.Id == viewModel.Id);

            if (!string.IsNullOrEmpty(viewModel.Part))
            {
                channel.Part = viewModel.Part;
            }
            if (!string.IsNullOrEmpty(viewModel.IndexName))
            {
                channel.IndexName = viewModel.IndexName;
            }
            if (viewModel.MeasurementId != null)
            {
                channel.MeasurementId = viewModel.MeasurementId;
            }
            if (!string.IsNullOrEmpty(viewModel.Direction))
            {
                channel.Direction = viewModel.Direction;
            }

代码运行良好,但我在这里使用了很多 if 语句,这对我来说并不是很有效。你能建议我改变一下,比如使用其他语法或结构而不是 if 语句来使我的代码更简洁、更精巧 "pro"?

如果这些是字段而不是属性,您可以使用这样的东西:

void ReplaceIfNotEmpty(ref string destination, string source)
{
    if (!string.IsNullOrEmpty(source))
    {
        destination = source;
    }
}

然后就是

ReplaceIfNotEmpty(ref channel.Part, viewModel.Part);

如果只是 if 困扰您,您可以使用条件运算符:

channel.Part = string.IsNullOrEmpty(viewModel.Part) ? 
               channel.Part : viewModel.Part;
etc.

当然 总是Part 调用 set 访问器,这很好,除非其中有逻辑(更改跟踪等)如果在值没有真正改变时调用它会很糟糕。

您也可以将条件运算符重构为一个方法,但没有其他方法 有条件地 设置值而不使用 if

只要您的通道对象的属性除了更改值(即触发事件)之外没有任何副作用,您就可以这样做:

string PickNonEmptyOrDefault(string value, string deflt)
{
    return String.IsNullOrEmpty(value) ? deflt : value;
}

...

channel.Part = PickNonEmptyOrDefault(viewModel.Part, channel.Part);
channel.IndexName = PickNonEmptyOrDefault(viewModel.IndexName, channel.IndexName);
etc.

顺便说一句,我想知道是否有一种方法可以在不意外地影响您的 属性 的情况下完成此操作。诀窍是使用反射并使用 PropertyInfo 对象来完成您的工作:

    class Foo
    {
        public string Bar { get; set; }
        public string Baz { get; set; }
        public override string ToString()
        {
            return (Bar ?? "") + " " + (Baz ?? "");
        }
    }
    delegate void propsetter(string prop, string value);

    private static void SetOnNonEmpty(PropertyInfo pi, Object o, string value)
    {
        if (pi.PropertyType != typeof(string))
            throw new ArgumentException("type mismatch on property");

        if (!String.IsNullOrEmpty(value))
            pi.SetValue(o, value);
    }

    static void Main(string[] args)
    {

        var myObj = new Foo();
        myObj.Baz = "nothing";
        PropertyInfo piBar = myObj.GetType().GetProperty("Bar");
        PropertyInfo piBaz = myObj.GetType().GetProperty("Baz");

        SetOnNonEmpty(piBar, myObj, "something");
        SetOnNonEmpty(piBaz, myObj, null);
        Console.WriteLine(myObj);
    }

输出something nothing

老实说,我不建议这样做,因为它并没有真正增加可读性,而且感觉很恶心。

我更倾向于编写一段代码来反映您的视图模型的属性并调用 Func<string, string> 以在您的数据模型中获取相应的 属性 名称,然后如果 returns 非空且 属性 类型匹配,则在视图对象上调用 getter 并将其传递给数据对象上的 setter。

只有当我多次这样做时,我才会这样做。

你写的代码绝对没有问题。

如果您的 objective 代码行数较少,您可以这样做,但我认为这只会增加不必要的复杂性。

channel.Part = string.IsNullOrWhiteSpace(viewModel.Part) ? channel.Part : viewModel.Part;
channel.IndexName = string.IsNullOrWhiteSpace(viewModel.IndexName) ? channel.IndexName: viewModel.IndexName;
channel.MeasurementId = viewModel.MeasurementId == null ? channel.MeasurementId : viewModel.MeasurementId;
channel.Direction = string.IsNullOrWhiteSpace(viewModel.Direction) ? channel.Direction : viewModel.Direction;

请注意,我已将您的呼叫从 IsNullOrEmpty 切换到 IsNullOrWhiteSpace

值为“ ”(一个或多个空格)的字符串将通过 IsNullOrEmpty 检查,您可能不希望这样做。

您还可以像这样对可空类型(但不是空字符串)使用合并运算符...

channel.MeasurementId = viewModel.MeasurementId ?? channel.MeasurementId;

你的代码没问题。甚至 Jon Skeet 使用 if 语句。

如果您想要性能最佳的代码,请保持这样。如果您想让您的代码看起来 pro,请使用此处其他人提出的任何建议。我的意见:保持原样。