简体   繁体   中英

LINQ Not Equals Not Working?

I'm trying to solve a problem where I need to manage an array of number ranges and I need to ensure that no number ranges in the collection collide with each other. For those of who who already figured it out: yes, I'm talking about networks, but I'm trying to simplify for this post. :-)

It took me a minute (or maybe two), but I came up with the following logic test:

  1. Determine if the existing ending (last) is less than the new beginning (new first).
  2. Determine if the existing beginning (first) is greater than the new ending (new last).
  3. If the result of #1 is not the same as the result of #2, then the ranges do not collide.

As best as I can tell (and replicate in Excel), this is sound logic. However, when I try to write this logic in LINQ in C# and subsequently execute in PowerShell, it doesn't work. I apologize for the lengthy PowerShell output in advance.

How should I be writing this logic in LINQ? Where did I go wrong?

C# Code:

public class NumberRange
{
    public int First;
    public int Last;

    public NumberRange()
    {
    }

    public NumberRange(int first, int last)
    {
        First = first;
        Last = last;
    }
}

public class NumberRangeCollection : Collection<NumberRange>
{
    protected override void InsertItem(int index, NumberRange item)
    {
        NumberRange[] existingItem = this.Where(x => ((x.Last < item.First) != (x.First > item.Last))).ToArray();
        if (existingItem.Any()) throw new ArgumentException("New range collides with an existing range.", "item");

        base.InsertItem(index, item);
    }
}

PowerShell commands:

PS> $range1 = New-Object TestLibrary.NumberRange -ArgumentList @(3, 4)
PS> $range2 = New-Object TestLibrary.NumberRange -ArgumentList @(4, 5)
PS> $range3 = New-Object TestLibrary.NumberRange -ArgumentList @(5, 6)
PS> $bigrange = New-Object TestLibrary.NumberRange -ArgumentList @(3, 6)
PS> $b = New-Object TestLibrary.NumberRangeCollection
PS> $b.Add($range1)
PS> $b.Add($bigrange) # This should fail, but doesn't
PS> $b | Format-Table -AutoSize

First Last
----- ----
    3    4
    3    6


PS> $b = New-Object TestLibrary.NumberRangeCollection
PS> $b.Add($range2)
PS> $b.Add($bigrange) # This should fail, but doesn't
PS> $b | Format-Table -AutoSize

First Last
----- ----
    4    5
    3    6


PS> $b = New-Object TestLibrary.NumberRangeCollection
PS> $b.Add($range3)
PS> $b.Add($bigrange) # This should fail, but doesn't
PS> $b | Format-Table -AutoSize

First Last
----- ----
    5    6
    3    6


PS> $b = New-Object TestLibrary.NumberRangeCollection
PS> $b.Add($range4)
PS> $b.Add($bigrange) # This should fail, does, but doesn't throw the right exception.
Exception calling "Add" with "1" argument(s): "Object reference not set to an instance of an object."
At line:1 char:1
+ $b.Add($bigrange)
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NullReferenceException

PS> $b | Format-Table -AutoSize
PS> $b = New-Object TestLibrary.NumberRangeCollection
PS> $b.Add($bigrange)
PS> $b.Add($range1) # This should fail, but doesn't
PS> $b.Add($range2) # This should fail, but doesn't
PS> $b.Add($range3) # WOOT!  The only one that works!
Exception calling "Add" with "1" argument(s): "New range collides with an existing range.
Parameter name: item"
At line:1 char:1
+ $b.Add($range3)
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

PS> $b.Add($range4) # This should fail, does, but doesn't throw the right exception.
Exception calling "Add" with "1" argument(s): "Object reference not set to an instance of an object."
At line:1 char:1
+ $b.Add($range4)
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NullReferenceException

PS> $b | Format-Table -AutoSize

First Last
----- ----
    3    6
    3    4
    4    5

Thank you, @JonSkeet, for your suggestion of rewriting it as I found the second problem doing that.

So, the answer to my question is two fold:

  1. The LINQ logic was sound (using !=), but the logic in InsertItem was reversed. I either needed to change != to == or change if (existingItem.Any()) to if (!existingItem.Any()) . I chose the former.
  2. $range4 didn't exist (leftover from other testing). sigh

Here is the completed working code (all in C#):

public class NumberRange
{
    public int First;
    public int Last;

    public NumberRange()
    {
    }

    public NumberRange(int first, int last)
    {
        First = first;
        Last = last;
    }
}

public class NumberRangeCollection : Collection<NumberRange>
{
    public NumberRange BigRange = new NumberRange(3, 6);
    public NumberRange Range1 = new NumberRange(3, 4);
    public NumberRange Range2 = new NumberRange(4, 5);
    public NumberRange Range3 = new NumberRange(5, 6);

    protected override void InsertItem(int index, NumberRange item)
    {
        NumberRange[] existingItem = this.Where(x => ((x.Last < item.First) == (x.First > item.Last))).ToArray();
        if (existingItem.Any()) throw new ArgumentException("New range collides with an existing range.", "item");

        base.InsertItem(index, item);
    }

    public NumberRangeCollection RunTest1()
    {
        Clear();
        Add(Range1);
        Add(BigRange);
        return this;
    }

    public NumberRangeCollection RunTest2()
    {
        Clear();
        Add(Range2);
        Add(BigRange);
        return this;
    }

    public NumberRangeCollection RunTest3()
    {
        Clear();
        Add(Range3);
        Add(BigRange);
        return this;
    }

    public NumberRangeCollection RunTest4()
    {
        Clear();
        Add(BigRange);
        try
        {
            Add(Range1);
        }
        catch
        {
        }
        try
        {
            Add(Range2);
        }
        catch
        {
        }
        try
        {
            Add(Range3);
        }
        catch
        {
        }
        return this;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM