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