Home > Software design >  Blank or reusable List<t> outside If statement C#
Blank or reusable List<t> outside If statement C#

Time:07-30

I can't inherit the idea of Nothing from Vb.net code. but I wish to declare a list type in a if statement e.g.

Var LabourUnits;//does not work    

if (LabourLinesFor == "Quote")
{
    LabourUnits = context.QuoteLabourUnitsViews.Where(x => x.QuoteId == RelatedId).OrderBy(x => x.DisplayOrder).ToList();
    ShowDiscounts = context.QuoteLabourUnitsViews.Where(x => x.QuoteId == RelatedId && x.UnitDiscountExVat > 0).Any();
    VATPercent = default;
}
else if (LabourLinesFor == "Refund")
{
    LabourUnits = context.RefundLabourUnitsViews.Where(x => x.RefundId == RelatedId).ToList();
    VATPercent = context.RefundsViews.Where(x => x.RefundId == RelatedId).Select(x => x.Vatpercent).FirstOrDefault();
}

if(LabourUnits.Count > 0)
{
    //do something
}

as the type is declared in the if statement it does not feed out to the outer var, and therefore cannot be used. Is there a way of creating a blank or carrier List? Updated Have used a real example, in vb LabourUnits could be declared as nothing but would then be accessible

further the VB -

Dim LabourUnits = Nothing
  If LabourLinesFor = "Quote" Then
            LabourUnits = dal.dc.QuoteLabourUnitsViews.Where(Function(x) x.QuoteID = RelatedID).OrderBy(Function(x) x.DisplayOrder).ToList
            ShowDiscounts = dal.dc.QuoteLabourUnitsViews.Where(Function(x) x.QuoteID = RelatedID And x.UnitDiscountExVat > 0).Any
            VATPercent = CType(Nothing, Decimal?)
        ElseIf LabourLinesFor = "Refund" Then
            LabourUnits = dal.dc.RefundLabourUnitsViews.Where(Function(x) x.RefundID = RelatedID).ToList
            VATPercent = dal.dc.RefundsViews.Where(Function(x) x.RefundID = RelatedID).Select(Function(x) x.VATPercent).FirstOrDefault
End If
If LabourUnits.Count > 0  Then
'do something
End If

Failed attempt...

 List<JobLabourUnitsView> jLabourUnits = new();
            List<QuoteLabourUnitsView> qLabourUnits=new();
            List<RefundLabourUnitsView> rLabourUnits = new();
            List<PartsOnlyLabourView> pLabourUnits = new();
            List<JobLabourUnitsView> prevLabourUnits = new();



        


            decimal? VATPercent = default;

            var ShowDiscounts = default(bool);

            if (Preview)
            {
               prevLabourUnits = GetPreviewLabourUnits();
            }
            else if (LabourLinesFor == "Job")
            {
                
                jLabourUnits = context.JobLabourUnitsViews.Where(x => x.JobId == RelatedId).OrderBy(x => x.DisplayOrder).ToList();
                ShowDiscounts = context.JobLabourUnitsViews.Where(x => x.JobId == RelatedId && x.UnitDiscountExVat > 0).Any();
                VATPercent = context.TblJobs.Where(x => x.JobId == RelatedId).Select(x => x.Vatpercent).FirstOrDefault();
               
            }

            else if (LabourLinesFor == "Quote")
            {
                qLabourUnits = context.QuoteLabourUnitsViews.Where(x => x.QuoteId == RelatedId).OrderBy(x => x.DisplayOrder).ToList();
                ShowDiscounts = context.QuoteLabourUnitsViews.Where(x => x.QuoteId == RelatedId && x.UnitDiscountExVat > 0).Any();
                VATPercent = default;
               
            }
            else if (LabourLinesFor == "Refund")
            {
               rLabourUnits = context.RefundLabourUnitsViews.Where(x => x.RefundId == RelatedId).ToList();
                VATPercent = context.RefundsViews.Where(x => x.RefundId == RelatedId).Select(x => x.Vatpercent).FirstOrDefault();
            }
            else if (LabourLinesFor == "PartsOnlySale")
            {
                pLabourUnits = context.PartsOnlyLabourViews.Where(x => x.PartsOnlySaleId == RelatedId).OrderBy(x => x.DisplayOrder).ToList();
                ShowDiscounts = context.PartsOnlyLabourViews.Where(x => x.PartsOnlySaleId == RelatedId && x.UnitDiscountExVat > 0).Any();
                VATPercent = context.TblPartsOnlySales.Where(x => x.PartsOnlySaleId == RelatedId).Select(x => x.Vatpercent).FirstOrDefault();
            }
            else if (LabourLinesFor == "CarSale")
            {

            }

            Object[] obj = {
        new { key = "0", value = jLabourUnits},
        new { key = "1", value = qLabourUnits},
        new { key = "2", value = rLabourUnits},
        new { key = "3", value = pLabourUnits},
         new { key = "4", value = prevLabourUnits}
    };

            int ticky = 0;
            Type mod;

            if(jLabourUnits.Count() > 0)
            {
                ticky = 0;
                mod = (Type)Activator.CreateInstance(typeof(JobLabourUnitsView));
            }
            else if(qLabourUnits.Count() > 0)
            {
                ticky = 1;
                mod = (Type)Activator.CreateInstance(typeof(QuoteLabourUnitsView));
            }
            else if(rLabourUnits.Count() > 0){
                ticky = 2;
                mod = (Type)Activator.CreateInstance(typeof(RefundLabourUnitsView));
            }
            else if(pLabourUnits.Count() > 0){
                ticky = 3;
                mod = (Type)Activator.CreateInstance(typeof(PartsOnlyLabourView));
            }
            else if(prevLabourUnits.Count() > 0){
                ticky = 4;
                mod = (Type)Activator.CreateInstance(typeof(JobLabourUnitsView));
            }
            IList<mod> LabourUnits = obj[ticky];

            if (LabourUnits.Count() > 0)
                //do something

This is totally unpleasant and doesn't work but as you can see have tried lateral methods...

CodePudding user response:

As Damien pointed out, you need to specify the type. If you use 'var' keyword, you can't leave the variable uninitialized.

var list; // will not work, the type is not known
List<string> list2; // will work, the type is clear

In this case, I would create a List<Interface> or List<AbstractClass> and then depending on what I need, have the list contain one or another object of a class that implement this interface or inherit from the abstract class.

List<IFruit> fruits = new();
fruits.Add(new Apple());
fruits.Add(new Orange());

interface IFruit { }
class Apple : IFruit { }
class Orange : IFruit { }

CodePudding user response:

I'm not sure that you fully understand what's going on in the VB or the C#, so I'll go over it all.

In VB, Option Strict determines whether strict typing is enforced (On) or not (Off). Option Strict Off is the default, to make things easier for beginners and VB6 developers but a good VB.NET developer will turn it On immediately and leave it On in all but those cases where late-binding is required, e.g. Office Automation. Even then, it should be On at the project level and Off at the file level for only those files that require it. Partial classes should be used to keep the amount of code in those files to an absolute minimum.

With Option Strict Off, you can do this in VB:

Dim someVariable

In that case, someVariable defaults to type Object. That code is functionally equivalent to this:

Dim someVariable As Object

With Option Strict On and strict typing enforced, the second code snippet would be required.

With the introduction of Option Infer, variable data types can now be inferred from an initialising expression. Whether Option Strict is On or Off, with Option Infer On you can do this:

Dim someVariable = someExpression

and the data type of someVariable will be inferred from the type of someExpression, rather than defaulting to Object. In C#, the use of var works the same way, inferring the variable type from the initialising expression. This means that var only makes sense when there is such an expression. This is valid C# code: Option Strict is On or Off, with Option Infer On you can do this:

var someVariable = someExpression;

but this makes no sense:

var someVariable;

With Option Strict Off in VB, late binding is allowed. That means that the compiler will allow you to specify member access on an Object reference that it cannot confirm and it is up to you to ensure that the actual object at run time has the specified member. This is allowed with Option Strict Off:

Dim someVariable As Object = "Hello World"
Dim someOtherVariable

someOtherVariable = "Hello World"

Dim x Integer = someVariable.Length
Dim y Integer = someOtherVariable.Length

With Option Strict On, that code would not compile. In C#, you can get basically the same functionality using dynamic:

dynamic someVariable = "Hello World";
dynamic someOtherVariable;

someOtherVariable = "Hello World";

int x = someVariable.Length;
int y = someOtherVariable.Length;

Again, though, you should not be using dynamic all over the place because you can't be bothered to write good strongly-typed code. It should be used where it adds genuine value.

In your case, if the reason you want to use a single variable is to use the Count property then you can go for the lowest common denominator, which would be ICollection. Any List<T> can be assigned to a variable of that type, as can arrays and various other collections. ICollection exposes a Count property and it extends IEnumerable, so you can run a foreach loop over it too. If you use IList instead then you can also index the list to get or set an item as well as Add, Remove and so on.

Using any of those interfaces, each item will be an Object reference, so you cannot do anything that is specific to the item type. You could do anything with an item that wasn't common to all possible types anyway, which you could do if you were to have each item type implement the same interface.

If you want any more than that, you're going to have to explain what you actually want to achieve by using the same variable for different types of lists. You've shown the use of Count and I've covered that. is there anything relevant that you didn't actually explain in your question?

  • Related