我有两个接口IndexField
和BatchField
。 他们没有共享相同的基类。它们都具有Name
属性。所以给定这种方法
private void Initialize(IEnumerable fields)
{
List<string> fieldNames = new List<string>();
foreach (object fld in fields)
{
string name = string.Empty;
if (fld is IndexField indexField)
{
name = indexField.Name;
}
else if (fld is BatchField batchField)
{
name = batchField.Name;
}
fieldNames.Add(name);
}
// Do something ...
}
我传入了batchfields
或indexfields
的集合作为参数。我想将name属性分配给新的字符串列表。
我知道我可以通过List<string> fieldNames
作为方法参数,但是我的问题是:
尽管我不知道正确的接口类型,有没有办法避免if语句并调用Name
属性?
我从这段代码开始,认为这是一个很好的代码,但也许有些类似
List<string> fieldNames = new List<string>();
foreach (object fld in fields)
{
fieldNames.Add(fld.Name); // fld might be an IndexField or BatchField interface
}
答案 0 :(得分:4)
通过反射获取属性
private object GetPropertyValue(object item, string property)
{
// No value
object value = null;
var pi = item.GetType().GetProperty(property);
// If we have a valid property, get the value
if (pi != null)
value = pi.GetValue(item, null);
// Done
return value;
}
这是实现方法:
private void Initialize(IEnumerable fields)
{
List<string> fieldNames = new List<string>();
foreach (object fld in fields)
{
string name = GetPropertyValue(fld, "Name").ToString();
fieldNames.Add(name);
}
// Do something ...
}
我无法测试您的代码,因此您可能需要对其进行调整。
在此处使用反射可能是不好的做法。您可能应该修复接口或为方法创建重载。
答案 1 :(得分:4)
另一个使用linq的衬板:
fieldNames.AddRange(
fields.Select(obj => (obj as IndexField)?.Name ?? (obj as BatchField)?.Name));
See a live demo on .Net fiddle.
尽管理想情况下,您应该更改IndexField
和BatchField
以实现我在问题注释中所写的通用接口。
答案 2 :(得分:1)
简单地使用
SitemapSpider
答案 3 :(得分:1)
在最后一个foreach
语句中,您无法访问Name
属性,因为fld
是对象类型。您可以创建另一个interface
并从中继承两个interfaces
,然后将上一个fld
中的foreach
类型从object
更改为新创建的接口。像这样:
public interface IBaseInterface
{
String Name { get; set; }
}
public interface IndexField: IBaseInterface
{
}
public interface BatchField: IBaseInterface
{
}
然后:
foreach (BaseInterface fld in fields)
{
fieldNames.Add(fld.Name);
}
或更简单的使用LINQ:
List<string> fieldNames = (from IBaseInterface fld in fields select fld.Name).ToList();