2

所以我从数据库中提取了一些信息,我需要将它映射到我的模型的属性。我的第一次尝试产生了一个大的 switch 语句,它遵循一个明显的模式。我想知道这个脆弱的代码是否可以以更动态的方式表达。

foreach (AttributeValue attributeValue in attributeValues)
{
    string label = attributes.First(a => a.ID == attributeValue.AttributeID).Name;
    switch (attributeValue.AttributeName)
    {
        case "TaskSequence":
            TaskSequenceLabel = label;
            break;
        case "TaskStatus":
            TaskStatusLabel = label;
            break;
        case "InstallChangeNumber":
            InstallChangeNumberLabel = label;
            break;
        case "InstallChangeStart":
            InstallChangeStartLabel = label;
            break;
        case "InstallChangeEnd":
            InstallChangeEndLabel = label;
            break;
        case "SubmittedDateTime":
            SubmittedDateTimeLabel = label;
            break;
        case "InstalledDateTime":
            InstalledDateTimeLabel = label;
            break;
    }
}

基本上我在想的是“将标签映射到具有标签值+“标签”的属性”

4

3 回答 3

2

你可以通过反射来做到这一点:

foreach (AttributeValue attributeValue in attributeValues)
{
    string label = attributes.First(a => a.ID == attributeValue.AttributeID).Name;
    string propertyName = attributeValue.AttributeName + "Label";
    PropertyInfo pi = GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
    // check for null, if it is possible that property not exists
    pi.SetValue(this, label, null);
}
于 2012-11-15T21:42:51.867 回答
2

您可以将标签存储在字典中,并通过其各自的键检索您需要的标签。这可以看作是Strategy Pattern的一个非常简单的实现。

var labels = new Dictionary<string, Label>();
labels.Add("TaskSequence", TaskSequenceLabel);
labels.Add("TaskStatus", TaskStatusLabel);
// etc.

attributeValues.ForEach(value => {
    string label = attributes.First(a => a.ID == value.AttributeID).Name;
    labels[value.AttributeName] = label;
});

如果您在多个地方需要它,您可以将其重构为自己的类:

public class MyLabels
{
    public Dictionary<string, Label> _labels =
                  new Dictionary<string< Label>();

    public MyLabels() {
        _labels.Add("TaskSequence", TaskSequenceLabel);
        _labels.Add("TaskStatus", TaskStatusLabel);
        // etc.
    }

    public Label Named(string name) {
        return _labels[name];
    }
}

// Usage:
var labels = new MyLabels();
attributeValues.ForEach(value => {
    string label = attributes.First(a => a.ID == value.AttributeID).Name;
    labels.Named(value.AttributeName) = label;
});
于 2012-11-15T21:50:20.720 回答
2

仅反射的解决方案当然可以解决问题。

但是,我会评估自定义属性的使用,您可以使用它来装饰感兴趣的成员。您可以使用它来指定您当前打开的属性名称。

对我来说,这似乎是一个比仅使用反射更强大的解决方案,因为它独立于TaskSequence->TaskSequenceLabel基于约定的映射。

使用仅反射的方法,如果有人更改 的名称TaskSequence,弄清楚为什么事情不再起作用可能比必要的更困难。然而,如果你有一个属性,你根本不在乎。当然,如果数据库中的字段名称发生更改,您会很在意。

编辑

让我添加一些代码来澄清一下(实际上是伪代码,我这里没有 Visual Studio 的副本)。我将假设它是您要填充的属性。

// here's the custom attribute. Ok, should probably be sealed and bla bla bla.

public class MapToAttribute : Attribute {
  readonly string _fieldName;

  public MapToAttribute(string fieldName) {
    _fieldName = fieldName;
  }
}

// here's your model
public class SomeModel {
  [MapTo("TaskSequence")]
  public int TaskSequence { get; set; }
}

// here's how you figure out which property have the MapTo attribute
from p in typeof(SomeModel).GetProperties() where p.IsDefined(typeof(MapToAttribute))

其余的留给读者练习。PropertyInfo.SetValue和朋友。

于 2012-11-15T21:50:48.473 回答