从未知接口获取 属性
Getting property from unknown interface
我有两个接口 IndexField
和 BatchField
。 它们不共享相同的碱基class。他们俩都有一个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
的集合作为参数。我想将名称 属性 分配给新的字符串列表。
我知道我可以将 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
}
通过反射获得 属性:
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 ...
}
我无法测试您的代码,因此您可能需要对其进行调整。
在这里使用反射可能是不好的做法。您可能应该修复您的接口或为您的方法创建重载。
如何简单地使用
var fieldNames = fields.OfType<IndexField>().Select(i => i.Name)
.Union(fields.OfType<BatchField>().Select(b => b.Name))
.ToList();
在您最后的 foreach
语句中,您无法访问 Name
属性,因为 fld
是对象类型。您可以创建另一个 interface
并从中继承您的两个 interfaces
,然后将上一个 foreach
中的 fld
类型从 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();
还有另一个使用 linq 的衬垫:
fieldNames.AddRange(
fields.Select(obj => (obj as IndexField)?.Name ?? (obj as BatchField)?.Name));
See a live demo on .Net fiddle.
尽管理想情况下您应该更改 IndexField
和 BatchField
以实现我在问题评论中所写的通用接口。
我有两个接口 IndexField
和 BatchField
。 它们不共享相同的碱基class。他们俩都有一个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
的集合作为参数。我想将名称 属性 分配给新的字符串列表。
我知道我可以将 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
}
通过反射获得 属性:
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 ...
}
我无法测试您的代码,因此您可能需要对其进行调整。
在这里使用反射可能是不好的做法。您可能应该修复您的接口或为您的方法创建重载。
如何简单地使用
var fieldNames = fields.OfType<IndexField>().Select(i => i.Name)
.Union(fields.OfType<BatchField>().Select(b => b.Name))
.ToList();
在您最后的 foreach
语句中,您无法访问 Name
属性,因为 fld
是对象类型。您可以创建另一个 interface
并从中继承您的两个 interfaces
,然后将上一个 foreach
中的 fld
类型从 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();
还有另一个使用 linq 的衬垫:
fieldNames.AddRange(
fields.Select(obj => (obj as IndexField)?.Name ?? (obj as BatchField)?.Name));
See a live demo on .Net fiddle.
尽管理想情况下您应该更改 IndexField
和 BatchField
以实现我在问题评论中所写的通用接口。