c#避免装箱和重复代码
c# avoiding boxing and repeated code
我有以下基础 class 和派生 classes。有两点我觉得我的代码有问题:
public class FieldCollection
{
public FieldCollection()
{
Fields = new List<FieldBase>();
}
public List<FieldBase> Fields { get; set; }
public void InitFieldList()
{
foreach (var item in DbFieldList)
{
if (item.Type == FieldTypes.int)
{
Fields.Add(new Field<int>());
}
else
if (item.Type == FieldTypes.string)
{
Fields.Add(new Field<string>());
}
...
};
}
public void SetFieldValue(string fieldName, object value)
{
FieldBase field = FindField(fieldName);
if ((field as FInt) != null)
{
(field as FInt).SetValue(Convert.ToInt32(value));
}
else
if ((field as FString) != null)
{
(field as FString).SetValue(Convert.ToString(value));
}
else
if ((field as FDate) != null)
{
(field as FDate).SetValue(Convert.ToDateTime(value));
};
}
public FieldBase FindField(string fieldName)
{
FieldBase field = Fields.FirstOrDefault(f => (String.Equals(f.Name, fieldName, StringComparison.CurrentCultureIgnoreCase)));
return field;
}
}
public abstract class FieldBase
{
public string Name { get; set; }
}
public class FInt : FieldBase
{
public void SetValue(int value)
{
}
}
public class FString : FieldBase
{
public void SetValue(string value)
{
}
}
public class FDate : FieldBase
{
public void SetValue(DateTime value)
{
}
}
- 重复:如果未来出现新的派生class,那么我将不得不添加额外的if语句等等。
if ((field as FInt) != null)
{
(field as FInt).SetValue(Convert.ToInt32(value));
}
else
if ((field as FString) != null)
{
(field as FString).SetValue(Convert.ToString(value));
}
else
if ((field as FDate) != null)
{
(field as FDate).SetValue(Convert.ToDateTime(value));
};
- 装箱和拆箱:我被迫根据派生 class 的类型将对象值转换为所需类型:
(field as FInt).SetValue(Convert.ToInt32(value));
(field as FString).SetValue(Convert.ToString(value));
(field as FDate).SetValue(Convert.ToDateTime(value));
我对如何设计这些 classes 以克服上述问题感兴趣。
非常感谢您的帮助。
您可以通过使用泛型重写代码来同时解决这两个问题(代码重复和装箱):
public class FieldCollection
{
public FieldCollection()
{
Fields = new List<FieldBase>();
}
public List<FieldBase> Fields { get; set; }
public void SetFieldValue<T>(string fieldName, T value)
{
var field = FindField<T>(fieldName);
field.SetValue(value);
}
public Field<T> FindField<T>(string fieldName)
{
return Fields.OfType<Field<T>>()
.FirstOrDefault(f => (String.Equals(f.Name, fieldName, StringComparison.CurrentCultureIgnoreCase)));
}
}
public abstract class FieldBase
{
public string Name { get; set; }
}
public class Field<T> : FieldBase
{
public void SetValue(T value)
{
}
}
对于 InitFieldList
,您可以使用 lambda 字典。例如:
private Dictionary<FieldTypes, Func<FieldBase>> FieldInitializers = new Dictionary<FieldTypes, Func<FieldBase>>
{
{ FieldTypes.int, () => new Field<int>() },
{ FieldTypes.string, () => new Field<string>() }
}
那么只需浏览一下字典即可:
public void InitFieldList()
{
foreach (var item in DbFieldList)
{
Fields.Add(FieldInitializers[item.Type].Invoke());
}
}
我有以下基础 class 和派生 classes。有两点我觉得我的代码有问题:
public class FieldCollection
{
public FieldCollection()
{
Fields = new List<FieldBase>();
}
public List<FieldBase> Fields { get; set; }
public void InitFieldList()
{
foreach (var item in DbFieldList)
{
if (item.Type == FieldTypes.int)
{
Fields.Add(new Field<int>());
}
else
if (item.Type == FieldTypes.string)
{
Fields.Add(new Field<string>());
}
...
};
}
public void SetFieldValue(string fieldName, object value)
{
FieldBase field = FindField(fieldName);
if ((field as FInt) != null)
{
(field as FInt).SetValue(Convert.ToInt32(value));
}
else
if ((field as FString) != null)
{
(field as FString).SetValue(Convert.ToString(value));
}
else
if ((field as FDate) != null)
{
(field as FDate).SetValue(Convert.ToDateTime(value));
};
}
public FieldBase FindField(string fieldName)
{
FieldBase field = Fields.FirstOrDefault(f => (String.Equals(f.Name, fieldName, StringComparison.CurrentCultureIgnoreCase)));
return field;
}
}
public abstract class FieldBase
{
public string Name { get; set; }
}
public class FInt : FieldBase
{
public void SetValue(int value)
{
}
}
public class FString : FieldBase
{
public void SetValue(string value)
{
}
}
public class FDate : FieldBase
{
public void SetValue(DateTime value)
{
}
}
- 重复:如果未来出现新的派生class,那么我将不得不添加额外的if语句等等。
if ((field as FInt) != null) { (field as FInt).SetValue(Convert.ToInt32(value)); } else if ((field as FString) != null) { (field as FString).SetValue(Convert.ToString(value)); } else if ((field as FDate) != null) { (field as FDate).SetValue(Convert.ToDateTime(value)); };
- 装箱和拆箱:我被迫根据派生 class 的类型将对象值转换为所需类型:
(field as FInt).SetValue(Convert.ToInt32(value)); (field as FString).SetValue(Convert.ToString(value)); (field as FDate).SetValue(Convert.ToDateTime(value));
我对如何设计这些 classes 以克服上述问题感兴趣。
非常感谢您的帮助。
您可以通过使用泛型重写代码来同时解决这两个问题(代码重复和装箱):
public class FieldCollection
{
public FieldCollection()
{
Fields = new List<FieldBase>();
}
public List<FieldBase> Fields { get; set; }
public void SetFieldValue<T>(string fieldName, T value)
{
var field = FindField<T>(fieldName);
field.SetValue(value);
}
public Field<T> FindField<T>(string fieldName)
{
return Fields.OfType<Field<T>>()
.FirstOrDefault(f => (String.Equals(f.Name, fieldName, StringComparison.CurrentCultureIgnoreCase)));
}
}
public abstract class FieldBase
{
public string Name { get; set; }
}
public class Field<T> : FieldBase
{
public void SetValue(T value)
{
}
}
对于 InitFieldList
,您可以使用 lambda 字典。例如:
private Dictionary<FieldTypes, Func<FieldBase>> FieldInitializers = new Dictionary<FieldTypes, Func<FieldBase>>
{
{ FieldTypes.int, () => new Field<int>() },
{ FieldTypes.string, () => new Field<string>() }
}
那么只需浏览一下字典即可:
public void InitFieldList()
{
foreach (var item in DbFieldList)
{
Fields.Add(FieldInitializers[item.Type].Invoke());
}
}