Получение свойства из неизвестного интерфейса - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть два интерфейса 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
}

Ответы [ 4 ]

0 голосов
/ 05 ноября 2018

И еще один лайнер, используя linq:

fieldNames.AddRange(
     fields.Select(obj => (obj as IndexField)?.Name ?? (obj as BatchField)?.Name));

Смотрите живую демонстрацию на .Net fiddle.

Хотя в идеале вы должны изменить IndexField и BatchField, чтобы реализовать общий интерфейс, как я писал в комментариях к вопросу.

0 голосов
/ 05 ноября 2018

Как насчет простого использования

var fieldNames = fields.OfType<IndexField>().Select(i => i.Name)
    .Union(fields.OfType<BatchField>().Select(b => b.Name))
    .ToList();
0 голосов
/ 05 ноября 2018

В последнем операторе 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();
0 голосов
/ 05 ноября 2018

Получение недвижимости с отражением:

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 ...
}

Мне не удалось протестировать ваш код, поэтому вам, возможно, придется настроить его.

Использование отражения здесь, вероятно, плохая практика. Возможно, вам следует либо исправить ваши интерфейсы, либо создать перегрузки для вашего метода.

...