Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 19:46
    runfoapp[bot] edited #61367
  • 19:46
    runfoapp[bot] edited #61367
  • 19:31
    runfoapp[bot] edited #61367
  • 19:31
    runfoapp[bot] edited #61367
  • 19:23
    dotnet-bot closed #63406
  • 19:17
    cston synchronize #63461
  • 19:16
    runfoapp[bot] edited #61367
  • 19:16
    runfoapp[bot] edited #61367
  • 19:01
    runfoapp[bot] edited #61367
  • 19:01
    runfoapp[bot] edited #61367
  • 18:53
    Soreloser2 edited #63137
  • 18:52
    Soreloser2 edited #63137
  • 18:46
    runfoapp[bot] edited #61367
  • 18:46
    runfoapp[bot] edited #61367
  • 18:45
    msftbot[bot] milestoned #63415
  • 18:45
    msftbot[bot] milestoned #63415
  • 18:45

    jaredpar on main

    Regression test for ref struct … (compare)

  • 18:45
    jaredpar closed #62973
  • 18:45
    jaredpar closed #63415
  • 18:41
    dibarbet synchronize #63484
Joe4evr
@Joe4evr
and it needs to be told which assembly to load the analyzers from + possible dependencies, so there's room for improvement
Jon Evans
@glitch100
Checking them atm - cheers all
HaloFour
@HaloFour
Mohammad Hamdy Ghanem
@VBAndCs
I am using this extension method in c#:
    public static IEnumerator GetEnumerator(this System.ValueTuple<int, int, int> range)
    {
        int start = range.Item1;
        int end = range.Item2;
        int step = range.Item3;

        if (step > 0)
            for (int i = start; i <= end; i += step)
                yield return i;
        else
            for (int i = start; i >= end; i += step)
                yield return i;
    }
It allows me to use this code:
foreach (int i in (-10, 10, 3))
    Console.WriteLine(i);
I imported this method from C# to VB and I can also use it in for each:
image.png
Mohammad Hamdy Ghanem
@VBAndCs
image.png
But, this doesn't work:
    Sub Main(args As String())
        For Each i In (1, 10, 2).GetEnumerator()
            Console.WriteLine(i)
        Next
The starnge thing is that the opposite happens if I define the extensoin method in vb code!
Imports System.Runtime.CompilerServices

Public Module Tools
    <Extension>
    Public Iterator Function GetEnumerator(range As ValueTuple(Of Integer, Integer, Integer)) As IEnumerable
        Dim start = range.Item1
        Dim [end] = range.Item2
        Dim [step] = range.Item3

        If ([step] > 0) Then
            For i = start To [end] Step [step]
                Yield i
            Next
        Else
            For i = start To [end] Step [step]
                Yield i
            Next
        End If
    End Function

End Module
In this case, the (1, 10, 2).GetEnumerator()expression works, but (1, 10, 2) doesn't!
Why?
image.png
Mohammad Hamdy Ghanem
@VBAndCs
image.png
Yair Halberstadt
@YairHalberstadt
@VBAndCs because extension GetEnumerator is c# only
It's a C# 9.0 feature (which I implemented) and I never implemented it for VB.
Mohammad Hamdy Ghanem
@VBAndCs
This answers why it doesn't work when it is written in VB. But it works for vb when I reference it from C#. I am asking why?
And why .GetEnumerator works if it's written in vb and doesn't work in C#?
Is it ok to write a GetEnumerator function but can't call it directly?
Antony Male
@canton7
(Note that since your extension methods return the non-generic IEnumerable, you'll be boxing an int on every iteration of the loop, which is a fair chunk of unneeded garbage)
Mohammad Hamdy Ghanem
@VBAndCs
Thanks. I wasn't sure that IEnumerable<int> works and left it to try later, since I am just exploring new possibilities.
Yair Halberstadt
@YairHalberstadt
@VBAndCs what matters is which language the foreach is in, not which language has the GetEnumerator
It's a change to the spec for how foreach binds. There's nothing special about the GetEnumerator method. Just C# recognizes certain patterns when lowering foreach and VB a different set.
Antony Male
@canton7
My understanding of the question was that VB did manage to use an extension GetEnumerator, but only when the extension GetEnumerator was written in C#, not in VB?
Yair Halberstadt
@YairHalberstadt
If it did, that would be truly magical
Perhaps little mice sneaking in whilst I was sleeping and writing the code for that.
Mohammad Hamdy Ghanem
@VBAndCs
Seems that vb for each was able to consume C# getEnemurator b4 it was added to C# :). The question is why it can't consume the vb one? This is the code that vb generates:
[StandardModule]
public sealed class Tools
{
    [IteratorStateMachine(typeof(VB$StateMachine_0_GetEnumerator))]
    public static IEnumerable GetEnumerator(this (int, int, int) range)
    {
        VB$StateMachine_0_GetEnumerator vB$StateMachine_0_GetEnumerator = new VB$StateMachine_0_GetEnumerator(-2);
        vB$StateMachine_0_GetEnumerator.$P_range = range;
        return vB$StateMachine_0_GetEnumerator;
    }
}
I can't see what c# generates (except in il which I don't understand).
So, what is wrong with the vb state machine?
Yair Halberstadt
@YairHalberstadt
@VBAndCs I don't understand what you're saying by "Seems that vb for each was able to consume C# getEnemurator b4 it was added to C#"
Antony Male
@canton7
One difference is that it's missing the [Extension] attribute?
Mohammad Hamdy Ghanem
@VBAndCs

@VBAndCs I don't understand what you're saying by "Seems that vb for each was able to consume C# getEnemurator b4 it was added to C#"

Try it on yout machine. The getenumerator extension method works in vb when it is written in C# but doesn't work when it is written in VB! For Each in vb doesn what foreach in c# does in this matter, but seems the difference is in the generated state machine in both languages, or the way that Yield is implemented in both. Maybe it is a different attribute sued or a missing one. Seems something that can be fixed in vb to have the same functionality as c#.

Mohammad Hamdy Ghanem
@VBAndCs

One difference is that it's missing the [Extension] attribute?

this is the code I get back from ILSpy. I use the Extension attribute in the code as I posted before, and I show you that calling the .GetEnumerator explicitly works only for the one written in VB not C#.

Mohammad Hamdy Ghanem
@VBAndCs
Another thing to fix in C#: this code gives an error:
var e = (1, 2).GetEnumerator();
although I defined a GetEnumerator extension method!
Making it works on foreach is nice, but it should also work everywhere.
@VBAndCs Note that your extension method is on (int, int, int), but you're calling it on (int, int) just above. Those are different types
Aha, looking more closely at your screenshots, you're mixing up IEnumerable and IEnumerator.
  1. Your C# method returns IEnumerator
  2. This image image.png shows VB is complaining when you have a ForEach loop over an IEnumerator
  3. Your VB extension method returns IEnumerable, not IEnumerator (so it's different to the C# version)
  4. This image image.png shows VB is fine when you have a ForEach loop over an IEnumerable
Antony Male
@canton7
Fix up your VB extension method, and it works fine: https://dotnetfiddle.net/CQwNgG
@YairHalberstadt Looks like those mice were hard at work
Mohammad Hamdy Ghanem
@VBAndCs
My bad :D. But nice surprise that VB supports it :)
Seems I used the auto completion without paying attention. The two words are visually so close :)
But since when this is working in VB?
Mohammad Hamdy Ghanem
@VBAndCs

@VBAndCs Note that your extension method is on (int, int, int), but you're calling it on (int, int) just above. Those are different types

I have a two-item version.

using System;
using System.Collections;
using System.Runtime.CompilerServices;

foreach (int i in 20..10)
    Console.WriteLine(i);

foreach (int i in (10, -10))
    Console.WriteLine(i);

foreach (int i in (-10, 10, 3))
    Console.WriteLine(i);


public static class Extensions
{
    public static IEnumerator GetEnumerator(this System.Range range)
    {
        int start = range.Start.Value;
        int end = range.End.Value;
        if (end > start)
            for (int i = start; i <= end; i++)
                yield return i;
        else
            for (int i = start; i >= end; i--)
                yield return i;
    }

    public static IEnumerator GetEnumerator(this System.ValueTuple<int, int> range)
    {
        int start = range.Item1;
        int end = range.Item2;
        if (end > start)
            for (int i = start; i <= end; i++)
                yield return i;
        else
            for (int i = start; i >= end; i--)
                yield return i;
    }

    public static IEnumerator GetEnumerator(this System.ValueTuple<int, int, int> range)
    {
        int start = range.Item1;
        int end = range.Item2;
        int step = range.Item3;

        if (step > 0)
            for (int i = start; i <= end; i+=step)
                yield return i;
        else
            for (int i = start; i >= end; i += step)
                yield return i;
    }

}
Antony Male
@canton7
... and that works fine when you do var e = (1, 2).GetEnumerator()
Joe4evr
@Joe4evr

VB is complaining when you have a ForEach loop over an IEnumerator

of note, C# would do the same thing - there's an open-standing request to allow foreach-ing over an enumerator

Yair Halberstadt
@YairHalberstadt
@canton7 maybe it always worked in VB... I definitely didn't add it.
Mohammad Hamdy Ghanem
@VBAndCs
Thanks. This was helpful :). At least we discovered something new in VB.NET :).
Michael Fry
@nth-commit
Does anyone know of any guides which describe the relationship/non-relationship between the semantic model and System.Reflection? It's something I bump into all the time and haven't quite taken the time to understand. I am super familiar with navigating around System.Reflection and doing dynamic type stuff. Not so familiar with navigating around the semantic model (e.g. Compilation, ITypeSymbol). It would be nice if there was something I could read through which would help relate my familiarity with the former to the latter.