diff --git a/FrameworkFeatureConstants.props b/FrameworkFeatureConstants.props
index 819d8f1d..6912a671 100644
--- a/FrameworkFeatureConstants.props
+++ b/FrameworkFeatureConstants.props
@@ -4,7 +4,7 @@
$(DefineConstants);INDEX_OF_CHAR_COMPARISONTYPE_SUPPORTED;TIMESPAN_MULTIPLY_SUPPORTED;SPLIT_ACCEPTS_STRING_SEPARATOR;LAZY_RETURN_CONSTRUCTOR;QUEUE_TRY_OVERLOADS;OPTIMIZED_ELEMENT_AT;RANGE_SUPPORTED;READ_ONLY_SPAN_SUPPORTED;INDEX_TYPE;JOIN_TO_STRING_CHAR_SEPARATOR;REMOVE_EXTENSION
- $(DefineConstants);SYSTEM_INDEX_SUPPORTED;IP_END_POINT_TRY_PARSE_SUPPORTED
+ $(DefineConstants);SYSTEM_INDEX_SUPPORTED;IP_END_POINT_TRY_PARSE_SUPPORTED;OPTIMIZED_FIRST_LAST_OR_DEFAULT
$(DefineConstants);SET_CURRENT_STACK_TRACE_SUPPORTED;DYNAMICALLY_ACCESSED_MEMBERS_ATTRIBUTE_SUPPORTED
diff --git a/Funcky.Test/Extensions/EnumerableExtensions/FirstSingleLastOrNoneTest.cs b/Funcky.Test/Extensions/EnumerableExtensions/FirstSingleLastOrNoneTest.cs
index 3a526666..ce90a8ab 100644
--- a/Funcky.Test/Extensions/EnumerableExtensions/FirstSingleLastOrNoneTest.cs
+++ b/Funcky.Test/Extensions/EnumerableExtensions/FirstSingleLastOrNoneTest.cs
@@ -1,5 +1,7 @@
#pragma warning disable SA1010 // StyleCop support for collection expressions is missing
using System.Collections;
+using Funcky.Test.TestUtils;
+using Xunit.Sdk;
namespace Funcky.Test.Extensions.EnumerableExtensions;
@@ -24,6 +26,21 @@ public void GivenAnEnumerableSingleOrNoneGivesTheCorrectOption(List valueEn
ExpectedSingleOrNoneBehaviour(valueEnumerable, () => referenceEnumerable.SingleOrNone().Match(none: false, some: True));
}
+#if OPTIMIZED_FIRST_LAST_OR_DEFAULT
+ [Fact]
+#else
+ [Fact(Skip = ".NET Framework 4.8 doesn't optimize these methods")]
+#endif
+ public void DoesNotEnumerateListsWhenCalledWithoutPredicate()
+ {
+ var list = new FailOnEnumerateListWrapper(["foo"]);
+ _ = list.FirstOrNone();
+ _ = list.LastOrNone();
+
+ // SingleOrNone does not specialize for `Select`ed lists.
+ Assert.Throws(() => _ = list.SingleOrNone());
+ }
+
public static TheoryData, List> ValueReferenceEnumerables()
=> new()
{
diff --git a/Funcky.Test/TestUtils/FailOnEnumerateCollectionWrapper.cs b/Funcky.Test/TestUtils/FailOnEnumerateCollectionWrapper.cs
new file mode 100644
index 00000000..d829d0e2
--- /dev/null
+++ b/Funcky.Test/TestUtils/FailOnEnumerateCollectionWrapper.cs
@@ -0,0 +1,25 @@
+using System.Collections;
+using Xunit.Sdk;
+
+namespace Funcky.Test.TestUtils;
+
+internal class FailOnEnumerateCollectionWrapper(ICollection collection) : ICollection
+{
+ public bool IsReadOnly => true;
+
+ public int Count => collection.Count;
+
+ public IEnumerator GetEnumerator() => throw new XunitException("Should not be enumerated");
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ public void Add(T item) => throw new NotSupportedException();
+
+ public void Clear() => throw new NotSupportedException();
+
+ public bool Contains(T item) => collection.Contains(item);
+
+ public void CopyTo(T[] array, int arrayIndex) => collection.CopyTo(array, arrayIndex);
+
+ public bool Remove(T item) => throw new NotSupportedException();
+}
diff --git a/Funcky.Test/TestUtils/FailOnEnumerateListWrapper.cs b/Funcky.Test/TestUtils/FailOnEnumerateListWrapper.cs
new file mode 100644
index 00000000..af6edefd
--- /dev/null
+++ b/Funcky.Test/TestUtils/FailOnEnumerateListWrapper.cs
@@ -0,0 +1,16 @@
+namespace Funcky.Test.TestUtils;
+
+internal sealed class FailOnEnumerateListWrapper(IList list) : FailOnEnumerateCollectionWrapper(list), IList
+{
+ public T this[int index]
+ {
+ get => list[index];
+ set => throw new NotSupportedException();
+ }
+
+ public int IndexOf(T item) => list.IndexOf(item);
+
+ public void Insert(int index, T item) => throw new NotSupportedException();
+
+ public void RemoveAt(int index) => throw new NotSupportedException();
+}
diff --git a/Funcky/Extensions/EnumerableExtensions/FirstOrNone.cs b/Funcky/Extensions/EnumerableExtensions/FirstOrNone.cs
index 9515da05..db71ebd2 100644
--- a/Funcky/Extensions/EnumerableExtensions/FirstOrNone.cs
+++ b/Funcky/Extensions/EnumerableExtensions/FirstOrNone.cs
@@ -9,7 +9,9 @@ public static partial class EnumerableExtensions
[Pure]
public static Option FirstOrNone(this IEnumerable source)
where TSource : notnull
- => source.FirstOrNone(True);
+ => source
+ .Select(Option.Some)
+ .FirstOrDefault();
///
/// Returns the first element of the sequence as an that satisfies a condition or a value if no such element is found.
diff --git a/Funcky/Extensions/EnumerableExtensions/LastOrNone.cs b/Funcky/Extensions/EnumerableExtensions/LastOrNone.cs
index bb3f5b24..5899db01 100644
--- a/Funcky/Extensions/EnumerableExtensions/LastOrNone.cs
+++ b/Funcky/Extensions/EnumerableExtensions/LastOrNone.cs
@@ -9,7 +9,9 @@ public static partial class EnumerableExtensions
[Pure]
public static Option LastOrNone(this IEnumerable source)
where TSource : notnull
- => source.LastOrNone(True);
+ => source
+ .Select(Option.Some)
+ .LastOrDefault();
///
/// Returns the last element of a sequence that satisfies a condition as an or a value if no such element is found.
diff --git a/Funcky/Monads/Option/OptionExtensions.cs b/Funcky/Monads/Option/OptionExtensions.cs
index 35e0a661..0e516c64 100644
--- a/Funcky/Monads/Option/OptionExtensions.cs
+++ b/Funcky/Monads/Option/OptionExtensions.cs
@@ -1,6 +1,5 @@
using System.ComponentModel;
-#pragma warning disable RS0026
namespace Funcky.Monads;
public static partial class OptionExtensions