修改多个字符串字段

时间:2015-04-23 08:51:44

标签: c#

我有以下代码:

  class SearchCriteria
  {
        public string Name { get; set; }
        public string Email { get; set; }
        public string Company { get; set; }
        // ... around 20 fields follow

        public void Trim()
        {
            if( ! String.IsNullOrEmpty( Name ) )
            {
                 Name = Name.Trim();
            }

            if( ! String.IsNullOrEmpty( Email ) )
            {
                Email = Email.Trim();
            }

            // ... repeat for all 20 fields in the class.
        }
   }

我想编写一个能够正确修剪字段的函数,例如:

public void Trim()
{
    Trim( Name );
    Trim( Email );
    // ...
}

private static void Trim( ref string field )
{
    if( ! String.IsNullOrEmpty( field ) )
    {
        field = field.Trim();
    } 
}

当然,这在C#中是不允许的。 我有一个选择是编写一个帮助器并使用反射。 有没有其他方法可以实现这一点(反映在如此多的属性将在某个特定情况下肯定会受到性能影响,我无法负担得起)?

8 个答案:

答案 0 :(得分:11)

如果你已经有了代码,你在问什么?它的可读性和高效性。但也许最好让属性首先修剪传递的值。

class SearchCriteria
{
    private string _Name;
    public string Name
    {
        get { return _Name; }
        set { _Name = value == null ? null : value.Trim(); }
    }

    private string _Email;
    public string Email
    {
        get { return _Email; }
        set { _Email = value == null ? null : value.Trim(); }

    }

    private string _Company;
    public string Company
    {
        get { return _Company; }
        set { _Company = value == null ? null : value.Trim(); }

    }

    // ... around 20 fields follow
}

即使您可以使用反射方法。请注意,此代码始终难以理解和维护。即使它们不应该被修剪,它也会默默地修剪属性。例如,如果另一个开发人员扩展了这个类。

答案 1 :(得分:6)

public void Trim()
{
    Name = Trim( Name );
    Email = Trim( Email );
    // ...
}

private string Trim(string field )
{
    if( ! String.IsNullOrEmpty( field ) )
        field = field.Trim();
    return field;
}

修改

还尝试在属性的设置器中应用Trim功能

class SearchCriteria
{    
    private string Trim(string field)
    {
        if( ! String.IsNullOrEmpty( field ) )
            field = field.Trim();
        return field;
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = Trim(value); }
    }

    private string _email;
    public string Email
    {
        get { return _email; }
        set { _email = Trim(value); }

    }

    // ... other string properties
    // no public void Trim() method
}

答案 2 :(得分:3)

似乎矫枉过正..将时间保存在Trim(),浪费了字段声明中的时间

class SearchCriteria
{
    private Dictionary<string, string> _internalValues = new Dictionary<string, string>();
    public string Name { get { return _internalValues.ContainsKey("Name") ? _internalValues["Name"] : null; } set { _internalValues["Name"] = value; } }
    ....

    public void Trim()
    {
        foreach (var entry in _internalValues)
        {
            if (!string.IsNullOrEmpty(entry.Value)) _internalValues[entry.Key] = entry.Value.Trim();
        }
    }
}

答案 3 :(得分:3)

我更喜欢这种风格,重复是不可避免的,以保持可读性,但这将节省一些屏幕空间

class SearchCriteria
{
   public string Name { get; set; }
   public string Email { get; set; }
   public string Company { get; set; }


   public void Trim()
   {
        if(!String.IsNullOrEmpty(Name)) Name = Name.Trim();
        if(!String.IsNullOrEmpty(Email)) Email = Email.Trim();
        if(!String.IsNullOrEmpty(Company)) Company = Company.Trim();
   }
}

void Main()
{
    var criteria = new SearchCriteria();
    criteria.Email = "thing ";
    Console.WriteLine(criteria.Email.Length);
    criteria.Trim();
    Console.WriteLine(criteria.Email);
    Console.WriteLine(criteria.Email.Length);
}

答案 4 :(得分:3)

如果您没有使用自动属性,则可以使用ref。我同意这绝不是最佳选择。

class SearchCriteria
{
    private string _name;
    public string Name { get { return _name; } set { _name = value; }}
    public string Email { get; set; }
    public string Company { get; set; }
    // ... around 20 fields follow

    void Trim(ref string str)
    {
        if (!String.IsNullOrEmpty(str))
        {
            str = str.Trim();
        }
    }

    public void Trim()
    {
        Trim(ref _name);

        // ... repeat for all 20 fields in the class.
    }
}

答案 5 :(得分:2)

您可以按照以下方式修改代码

public void Trim()
{
    Name = Trim(Name);
    Email = Trim(Email);
    // ...
}

private static void Trim(string field)
{
    if( ! String.IsNullOrWhiteSpace( field ) )
    {
        field = field.Trim();
    }

    return field;
}

您无法通过引用传递属性,方法String.IsNullOrEmpty()会将空格视为非空,因此我使用了String.IsNullOrWhiteSpace()

答案 6 :(得分:2)

刚刚完成。我不知道这是不是一个好方法。但你可以像蒂姆·施梅尔特所说的那样反思。但是,他也指出代码更难维护,如果有人扩展它可能是问题。但这是一个如何做到这一点的例子:

class SearchCriteria
{
   public string Name { get; set; }
   public string Email { get; set; }
   public string Company { get; set; }
   // ... around 20 fields follow

   public void Trim()
   {
       typeof(SearchCriteria).GetProperties()
             .Where (w =>w.PropertyType==typeof(string))
             .ToList().ForEach(f=>
             {
                 var value=f.GetValue(this);
                 if(value!=null && !string.IsNullOrEmpty(value.ToString()))
                 {
                    f.SetValue(this,value.ToString().Trim(),null);
                 }
             });
   }
}

答案 7 :(得分:2)

反射显然不是最高效的解决方案,但通过一些修改和缓存,它仍然可以使用。

这是一个反射助手,它允许你创建mutator委托的集合并将其缓存在你的类中:

public static class ReflectionHelper
{
    public static IEnumerable<PropertyInfo> GetPropertiesOfType<THolder, TPropType>()
    {
        return typeof(THolder).GetPropertiesOfType(typeof(TPropType));
    }


    public static IEnumerable<PropertyInfo> GetPropertiesOfType(this Type holderType, Type propType)
    {
        if (holderType == null)
            throw new ArgumentNullException("holderType");
        if (propType == null)
            throw new ArgumentNullException("propType");

        return holderType
            .GetProperties()
            .Where(prop =>
                prop.PropertyType == propType); 
    }


    public static IEnumerable<Action<Func<TPropType, TPropType>>> CreateMutators<THolder, TPropType>(THolder holder)
    {
        if (holder == null)
            throw new ArgumentNullException("holder");

        return holder.GetType()
            .GetPropertiesOfType(typeof(TPropType))
            .Select(prop =>
                new
                {
                    getDelegate = (Func<TPropType>)Func.CreateDelegate(
                         typeof(Func<TPropType>), 
                         holder, 
                         prop.GetGetMethod()),
                    setDelegate = (Action<TPropType>)Action.CreateDelegate(
                         typeof(Action<TPropType>), 
                         holder, 
                         prop.GetSetMethod())
                })
            .Select(accessor =>
                (Action<Func<TPropType, TPropType>>)((mutate) =>
                {
                    var original = accessor.getDelegate();
                    var mutated = mutate(original);
                    accessor.setDelegate(mutated);
                }))
            .ToArray();
    }
}

类代码 - 缓存mutator并在Trim方法中使用它们:

class SearchCriteria
{
    public SearchCriteria()
    {
        this.Name = "adsfasd     ";
        this.Email = "       adsfasd     ";
        this.Company = "  asdf   adsfasd     ";

        this.stringMutators = ReflectionHelper.CreateMutators<SearchCriteria, String>(this);
    }

    public string Name { get; set; }
    public string Email { get; set; }
    public string Company { get; set; }
    // ... around 20 fields follow

    private IEnumerable<Action<Func<String, String>>> stringMutators;


    private String TrimMutate(String value)
    {
        if (String.IsNullOrEmpty(value))
            return value;

        return value.Trim();
    }

    public void Trim()
    {
        foreach (var mutator in this.stringMutators)
        {
            mutator(this.TrimMutate);
        }
    }

    public override string ToString()
    {
        return String.Format("Name = |{0}|, Email = |{1}|, Company = |{2}|",
            this.Name,
            this.Email,
            this.Company);
    }
}

主要代码:

            var criteria = new SearchCriteria();

            Console.WriteLine("Before trim:");
            Console.WriteLine(criteria);


            Console.WriteLine("After trim:");
            criteria.Trim();
            Console.WriteLine(criteria);

P.S。:然而,它不是非常直接或明确的解决方案,所以我建议选择“智能”设置器(getter),如其他答案中所述。或者,也许你可以尝试一些Aspect Oriented Programming approach