2014-11-25 6 views
3

Привет всем и спасибо, что посмотрели.C# FOREACH по нескольким спискам <> типы

Я не думаю, что это возможно, но я хотел бы сделать идентичный FOREACH через несколько возвращенных типов, без необходимости вырезать и вставлять код 4 раза. Все свойства dto2, dto3, dto4 и dto5 списки возвращаются одни и те же, за DataValue, что другой тип данных для каждого (INT, VARCHAR, BOOL и т.д.)

var dto2 = rd.EngDetailBitsList(dto.EngId); 
var dto3 = rd.EngDetailDateTimesList(dto.EngId); 
var dto4 = rd.EngDetailVarCharsList(dto.EngId); 
var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId); 

foreach (var x in dto2) 
{ 
    var propertyInfo = dto.GetType().GetProperty(x.ShortDescript, 
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
    if (propertyInfo != null) 
    { 
     propertyInfo.SetValue(dto, x.DataValue); 
    } 
} 

foreach (var x in dto3) 
{ 
    var propertyInfo = dto.GetType().GetProperty(x.ShortDescript, 
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
    if (propertyInfo != null) 
    { 
     propertyInfo.SetValue(dto, x.DataValue); 
    } 
} 

foreach (var x in dto4) 
{ 
    var propertyInfo = dto.GetType().GetProperty(x.ShortDescript, 
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
    if (propertyInfo != null) 
    { 
     propertyInfo.SetValue(dto, x.DataValue); 
    } 
} 

foreach (var x in dto5) 
{ 
    var propertyInfo = dto.GetType().GetProperty(x.ShortDescript, 
      BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
    if (propertyInfo != null) 
    { 
     propertyInfo.SetValue(dto, x.DataValue); 
    } 
} 
+2

Каковы типы 'dto2'-'dto5'? Они реализуют общий интерфейс с общим базовым классом с свойствами «ShortDescription» и «DataValue»? – MarcinJuraszek

+0

'ShortDescript' может возвращать разные значения, не так ли? Таким образом, вы можете установить разные свойства на 'dto'. – MarcinJuraszek

+0

@BrianRogers Я не понимаю. Для меня это имеет смысл. Несмотря на то, что тип всех элементов в списке одинаковый, свойство «ShortDescript» может возвращать разные значения «string», указывающие на разные свойства на 'dto'. – MarcinJuraszek

ответ

2

Есть два пути решения, что:

  1. Предполагая, что все dto2, dto3, dto4 и dto5 являются коллекциями некоторого типа T, который реализует общий интерфейс с ShortDescript и DataValue свойств, заявленных на нем.

    var dto2 = rd.EngDetailBitsList(dto.EngId); 
    var dto3 = rd.EngDetailDateTimesList(dto.EngId); 
    var dto4 = rd.EngDetailVarCharsList(dto.EngId); 
    var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId); 
    
    var source = dto2.Cast<MyInterface> 
           .Concat(dto3.Cast<MyInterface>) 
           .Concat(dto4.Cast<MyInterface>) 
           .Concat(dto4.Cast<MyInterface>); 
    
    
    var dtoType = dto.GetType(); 
    foreach (var x in source) 
    { 
        var propertyInfo = dtoType.GetProperty(x.ShortDescript, 
          BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
        if (propertyInfo != null) 
        { 
         propertyInfo.SetValue(dto, x.DataValue); 
        } 
    } 
    
  2. Без общего интерфейса вы можете использовать dynamic:

    var dto2 = rd.EngDetailBitsList(dto.EngId); 
    var dto3 = rd.EngDetailDateTimesList(dto.EngId); 
    var dto4 = rd.EngDetailVarCharsList(dto.EngId); 
    var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId); 
    
    var source = dto2.Cast<dynamic> 
           .Concat(dto3.Cast<dynamic>) 
           .Concat(dto4.Cast<dynamic>) 
           .Concat(dto4.Cast<dynamic>); 
    
    dto.GetType() 
    foreach (var x in source) 
    { 
        var propertyInfo = dtoType.GetProperty(x.ShortDescript, 
          BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
        if (propertyInfo != null) 
        { 
         propertyInfo.SetValue(dto, x.DataValue); 
        } 
    } 
    

    Это сделает ShortDescript и DataValue свойства должны быть решены во время выполнения, и вы получите исключение, если нет такой собственности на фактический тип.

+0

Блестяще простой, Марцин, и именно то, что я искал! Я использовал # 2 и динамическую трансляцию. Там есть пара опечаток, и Resharper заставил меня устранить несколько ненужных бросков, поэтому я вставлял точный код ниже в свой собственный ответ. Протестировано и работает точно так же, как мой первоначально вставленный код. Это мой первый вопрос, задающий вопрос после тысячи раз поиска решений, поэтому я не могу выдвигать кого-либо, потому что у меня нет репутации 15, или я бы это сделал. Но спасибо! –

0

Если кроме вас хотите, решение все-отражение, вы могли бы сделать метод как это:

static void SetDtoFields<T>(object targetDto, IEnumerable<T> fields) 
{ 
    Type fieldType = typeof(T); 

    var fieldNameProp = fieldType.GetProperty("ShortDescript"); 
    if (fieldNameProp == null || !fieldNameProp.CanRead) 
     return; 

    var dataValProp = fieldType.GetProperty("DataValue"); 
    if (dataValProp == null || !dataValProp.CanRead) 
     return; 

    Type targetType = targetDto.GetType(); 

    foreach (T field in fields) 
    { 
     var propToSet = targetType.GetProperty((string)fieldNameProp.GetValue(field), 
       BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 

     if (propToSet != null && propToSet.CanWrite && 
      propToSet.PropertyType.IsAssignableFrom(dataValProp.PropertyType)) 
     { 
      propToSet.SetValue(targetDto, dataValProp.GetValue(field)); 
     } 
    } 
} 

Затем в основном коде, вы можете просто сделать:

SetDtoFields(dto, rd.EngDetailBitsList(dto.EngId)); 
SetDtoFields(dto, rd.EngDetailDateTimesList(dto.EngId)); 
SetDtoFields(dto, rd.EngDetailVarCharsList(dto.EngId)); 
SetDtoFields(dto, rd.EngDetailVarCharMaxesList(dto.EngId)); 

Вот рабочий пример: https://dotnetfiddle.net/GhrJ0f

+0

Как вы собираетесь обращаться к свойствам DataValue и 'ShortDescript' на' x', когда объявлен как 'object'? Он даже не компилируется. – MarcinJuraszek

+0

Хорошая точка, вам также нужно использовать GetProperty. Я отредактирую. –

+0

Это мой первый вопрос, задающий вопрос здесь, когда тысячи раз ищут решения, поэтому я не могу выдвигать кого-либо, потому что у меня нет репутации 15, или я бы это сделал. –

-1

Вы можете попробовать это, что он делает, просто возьмите свой объект DTO, коллекцию и имя свойств, которые нужно получить и установить.

var dto2 = rd.EngDetailBitsList(dto.EngId); 
    var dto3 = rd.EngDetailDateTimesList(dto.EngId); 
    var dto4 = rd.EngDetailVarCharsList(dto.EngId); 
    var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId); 

    ObjectSetter(new object() /* test only */, dto2, "DataValue"); 

    private void ObjectSetter(object dto, string dtoProp, 
     IEnumerable items, string itemProperty) 
    { 
     foreach (var item in items) 
     { 
      var propertyInfo = item.GetType().GetProperty(dtoProp, 
       BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
      var itemValue = dto.GetType().GetProperty(itemProperty, 
       BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 

      if (propertyInfo != null) 
      { 
       propertyInfo.SetValue(item, itemValue.GetValue(dto)); 
      } 
     } 
    } 

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

 Task.Factory.StartNew(delegate() 
     { 
      ObjectSetter(new object() /* test only */, dto2, "DataValue"); 
     }); 

     Task.Factory.StartNew(delegate() 
     { 
      ObjectSetter(new object() /* test only */, dto3, "DataValue"); 
     }); 

     Task.Factory.StartNew(delegate() 
     { 
      ObjectSetter(new object() /* test only */, dto4, "DataValue"); 
     }); 

     Task.Factory.StartNew(delegate() 
     { 
      ObjectSetter(new object() /* test only */, dto5, "DataValue"); 
     }); 
+1

отрицательный голос без объяснения, да, это звучит отлично – DevEstacion

+0

Это было НЕ с нисходящим, не уверен, кто это сделал. Это мой первый вопрос, задающий вопрос после тысячи раз поиска решений, поэтому я не могу выдвигать кого-либо, потому что у меня еще нет репутации 15, или я бы это сделал. –

+0

Я тоже не спускал вниз. Но из того, что я вижу, вы вызываете ObjectSetter с 3 параметрами, но функция принимает 4 параметра ... Также «IEnumerable items» без типа, вероятно, не будет компилироваться. – Francisco

0

Я бы попробовал что-то вроде этого. Для вашего dto2, dto3, dto4, dto5 классов, сделать их разделить этот интерфейс:

public interface IDto 
{ 
    string ShortDescript {get;set;} 
    object ObjectValue {get;} 
} 

Implement ObjectValue на ваши объектах (показывая один как пример):

public partial class DetailBits // dto2 class maybe? 
{ 
    public object ObjectValue 
    { 
     get 
     { 
      return DataValue; 
     } 
    } 
} 

Затем создайте эту функцию:

public static void SetValues(DTO dto, IEnumerable<IDto> items) 
{ 
    foreach (var x in items) 
    { 
     var propertyInfo = dto.GetType().GetProperty(x.ShortDescript, 
       BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
     if (propertyInfo != null) 
     { 
      propertyInfo.SetValue(dto, x.ObjectValue); 
     } 
    } 
} 

Наконец, вы можете сделать это в вашей основной функции:

var dto2 = rd.EngDetailBitsList(dto.EngId).Cast<IDto>(); 
var dto3 = rd.EngDetailDateTimesList(dto.EngId).Cast<IDto>(); 
var dto4 = rd.EngDetailVarCharsList(dto.EngId).Cast<IDto>(); 
var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId).Cast<IDto>(); 

SetValues(dto, dto2); 
SetValues(dto, dto3); 
SetValues(dto, dto4); 
SetValues(dto, dto5); 
+0

Это мой первый вопрос, который задает вопрос после тысячи раз, ища решения, поэтому я не могу выдвигать кого-либо, потому что у меня нет репутации 15, или я бы это сделал. –

+0

Без проблем, если это поможет вам, все в порядке :) Просто проявляйте особую осторожность при динамических бросках, это может стать довольно грязным довольно быстро. GL – Francisco

0

Я использовал динамическое решение Martin's №2 с несколькими изменениями редактирования. Работает потрясающе!

 var dto2 = rd.EngDetailBitsList(dto.EngId); 
     var dto3 = rd.EngDetailDateTimesList(dto.EngId); 
     var dto4 = rd.EngDetailVarCharsList(dto.EngId); 
     var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId); 

     var source = dto2.Concat(dto3.Concat(dto4.Concat(dto5.Cast<dynamic>()))); 

     var dtoType = dto.GetType(); 
     foreach (var x in source) 
     { 
      var propertyInfo = dtoType.GetProperty(x.ShortDescript, 
        BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); 
      if (propertyInfo != null) 
      { 
       propertyInfo.SetValue(dto, x.DataValue); 
      } 
     } 
Смежные вопросы