1

in my program I am reading in an excel sheet and am doing some linq selections, which worked fine.

Problem: I tried to make a preselection by applying an If-statement. The variable will be assigned in every case (if/else) but the compiler doesn't see that. The compiler tells me to initialize the var beforehands but when I try that, I fail since I am only used to variables like sting, int or double which I can assign beforehands easily:

//This function takes the downloaded xlsx and makes selection of applicable items

var excel = new ExcelQueryFactory("list.xlsx");
//get all items with discount
if (onlyAcceptDiscountedItems == true)
{
    var discounts = from s in excel.Worksheet()
                    where s["Discount/Premium"].Cast<string>().StartsWith("-")
                    select s;
}
else
{
    var discounts = excel.Worksheet();
}
if (discounts.Count() != 0)
{
    //some application logic comes here
}

When I try To do it like that:

var excel = new ExcelQueryFactory("list.xlsx");ter code here
var discounts = excel.Worksheet();
if (onlyAcceptDiscountedItems == true)
{
    discounts = from s in excel.Worksheet()
                where s["Discount/Premium"].Cast<string>().StartsWith("-")
                select s;
}
if (discounts.Count() != 0)
{
    //some application logic comes here
}

I receive the following error at line 5 of the second codesnippet:

Error CS0266 Cannot implicitly convert type 'System.Linq.IQueryable' to 'LinqToExcel.Query.ExcelQueryable'. An explicit conversion exists (are you missing a cast?)

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
Julian Bechtold
  • 167
  • 1
  • 12
  • 3
    This is why `var` should only be used when the type is implied. The result of your LINQ statement is of a type that is not the same as `excel.Worksheet()` – maccettura Aug 15 '17 at 15:23
  • @hnefatl I believe its the same since i can pocess with both of them with no problems. – Julian Bechtold Aug 15 '17 at 15:26
  • 1
    In your first `if.. else` loop you are creating a local variable in both. So _"The variable will be assigned in every case"_ is not true - a **different** local variable is assigned in each case. That's why the compiler complains. – stuartd Aug 15 '17 at 15:27
  • 1
    @hnefatl: Nope, it's not the same type - that's the problem. The error message shows you the two types involved. – Jon Skeet Aug 15 '17 at 15:27

1 Answers1

7

I see three options, although there are others:

You could explicitly declare the type of variable you want, in which case you can initialize it separately in each case:

IQueryable<LinqToExcel.Row> discounts;
if (onlyAcceptDiscountedItems == true)
{
    discounts = from s in excel.Worksheet()
                where s["Discount/Premium"].Cast<string>().StartsWith("-")
                select s;
}
else
{
    discounts = excel.Worksheet();
}

You could use a conditional operator to initialize the variable:

var discounts = onlyAcceptDiscountedItems
    ? excel.Worksheet().Where(s => s["Discount/Premium"].Cast<string>().StartsWith("-"))
    : excel.Worksheet();

You could remove the redundancy of calling excel.Worksheet in two places:

IQueryable<LinqToExcel.Row> discounts = excel.Worksheet();
if (onlyAcceptDiscountedItems)
{
    discounts = discounts.Where(s => s["Discount/Premium"].Cast<string>().StartsWith("-"));
}

Additionally, you may want to use discounts.Any() instead of discounts.Count() > 0, given that you don't really care about the count.

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you so much. I chose solution 1 as the excelsheet contains several hundredthousand entries and I think the later two options may waste a lot of system ressources. – Julian Bechtold Aug 15 '17 at 15:34
  • 1
    @JulianBechtold: What makes you think any of them is more expensive? They really, really won't be. – Jon Skeet Aug 15 '17 at 15:35
  • you might also have given me a solution for my second problem which I didnt work on yet. `discounts.Count() > 0` gives a null exception when there are no items. I guess thats different with `discounts.Any()` ? – Julian Bechtold Aug 15 '17 at 15:35
  • 1
    @JulianBechtold: Neither of them should give you a `NullReferenceException` if there are no items at all. It sounds like you need to work on that part separately. Look into it, then provide a [mcve] in a new question if necessary. – Jon Skeet Aug 15 '17 at 15:36
  • for the second solution: iterating threw one table takes ~30 seconds, If you do it two times, wont it be 30 seconds? I dont know so much about the backgrounds yet. but my understanding would be that it first has to copy all elements of excel to discountsonly to iterete threw it again. – Julian Bechtold Aug 15 '17 at 15:39
  • @JulianBechtold Jon's LINQ queries are the same as yours. If you have performance issues then they are not due to Jon's answer, but another part of your code that you have not shown us. – maccettura Aug 15 '17 at 15:45
  • @Julian: What makes you think the second solution would iterate twice? It doesn't even call `Worksheet` twice, even leaving aside LINQ's deferred execution model. – Jon Skeet Aug 15 '17 at 16:17