1

sooo, friday night, best time for practicing :) I am struggling with this code:

var collection = rows.Skip(skipHeader ? 1 : 0)
    .Select(row =>
    {
        try
        {
            var tnew = new T();
            columns.ForEach(col =>
            {//for simplicity removed some code
                var val = worksheet.Cells[row, col.Column];
                if (col.Property.PropertyType == typeof(double))
                {
                    col.Property.SetValue(tnew, val.GetValue<double>());
                    return;
                }
                col.Property.SetValue(tnew, val.GetValue<string>());
            });

            return tnew;
        }
        catch (Exception e)
        {
            Console.WriteLine($"Could not create object from excel: {e}");
            //return default(T); dont do anything <<=== here i the problem
        }
    }).ToList();

The idea is this generic peace of code reads from excel a row and create new T object. However, if could be possible that there is more data in the row/excel that needs to be (metadata that i don't need). So basicly I need to check if all goes well. If it goes into the exception, then I know it doesn't fit the modal, so skip that row.

any thoughts?

Gilad Green
  • 36,708
  • 7
  • 61
  • 95
Roelant M
  • 1,581
  • 1
  • 13
  • 28
  • 3
    Don't use linq.. use a simple foreach loop.. much more readable. Also you must return something - you can maybe return `null` and then filter it out - but I think it is not a nice way here – Gilad Green Dec 15 '17 at 20:07
  • I can not return null, because compiler doesnt know if type i nullable. But I got it! – Roelant M Dec 15 '17 at 20:13

2 Answers2

1

when returning default(T) i got the right object. Afterwords, before the tolist, I can do a:

.Where(r => !EqualityComparer<T>.Default.Equals(r, default(T)))

so that skips the default initialisations:)

Roelant M
  • 1,581
  • 1
  • 13
  • 28
1

I'd recommend encapsulating your logic in a separate function:

public bool TryCreate<T>(YourType row, out T result) where T : class
{
    try
    {
        //set result to a properly initialized object
        return true;
    }
    catch(Exception e)
    {
        result = null; // or default(T) and remove constraint
        return false;
    }
}

and then like in this answer:

var result = rows.Skip(skipHeader ? 1 : 0)
                 .Select(row => new { Success = TryCreateT(row, out var value), value })
                 .Where(pair => pair.Success)
                 .Select(pair => pair.value);

As you commented that you cannot return null you can do one of two: Add to the method a generic constraint of class or use default(T)

Gilad Green
  • 36,708
  • 7
  • 61
  • 95