Reputation:
I have two interfaces IndexField
and BatchField
. They do not share the same base class. Both of them have a Name
Property. So given this method
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 ...
}
I pass in a collection of batchfields
or indexfields
as a parameter. I want to assign the name property to a new list of strings.
I know I can pass in List<string> fieldNames
as a method parameter but my question is:
Is there a way that I can avoid the if statements and call the Name
property although I don't know the correct interface type?
I started with this code and thought it would be a good one but maybe there is something like
List<string> fieldNames = new List<string>();
foreach (object fld in fields)
{
fieldNames.Add(fld.Name); // fld might be an IndexField or BatchField interface
}
Upvotes: 2
Views: 245
Reputation: 699
Getting a property with Reflection:
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;
}
Here's how to implement it:
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 ...
}
I was unable to test your code so you might need to tweak it.
Using Reflection here is probably bad practice. You should probably either fix your interfaces or create overloads for your method.
Upvotes: 3
Reputation: 39946
In your last foreach
statement, you can't access the Name
property, because the fld
is an object type. You can create another interface
and inherit your both interfaces
from it and then change the fld
type in your last foreach
from object
to that newly created interface. Something like this:
public interface IBaseInterface
{
String Name { get; set; }
}
public interface IndexField: IBaseInterface
{
}
public interface BatchField: IBaseInterface
{
}
And then:
foreach (BaseInterface fld in fields)
{
fieldNames.Add(fld.Name);
}
Or even simpler with LINQ:
List<string> fieldNames = (from IBaseInterface fld in fields select fld.Name).ToList();
Upvotes: 1
Reputation: 82474
And another one liner using linq:
fieldNames.AddRange(
fields.Select(obj => (obj as IndexField)?.Name ?? (obj as BatchField)?.Name));
See a live demo on .Net fiddle.
Though Ideally you should change IndexField
and BatchField
to implement a common interface as I wrote in the comments to the question.
Upvotes: 3
Reputation: 5121
How about just simply using
var fieldNames = fields.OfType<IndexField>().Select(i => i.Name)
.Union(fields.OfType<BatchField>().Select(b => b.Name))
.ToList();
Upvotes: 1