All things being being equal. Your question boils down to standard overload resolution rules.
Note : It's important when reading language specifications, that you don't end too soon or read too far. It's also important to read any relevant sub topics when promoted.
Since you are in the specs, let's work our way through them.
Given
public abstract class DbSet<TEntity> : IQueryable<TEntity>, IAsyncEnumerable<TEntity>, IInfrastructure<IServiceProvider>, IListSource
public interface IQueryable : IEnumerable
Extension methods
namespace System.Linq
{
public static TSource First<TSource>(this IQueryable<TSource> source)
...
}
namespace System.Linq
{
public static TSource First<TSource>(this IEnumerable<TSource> source)
...
}
Your example
DBSet<Student> studs = dbContext.Students;
var stu = studs.First();
The part of the specs you should be quoting is
Emphasis mine
7.6.5.2 Extension method invocations
...
- Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
- If the given namespace or compilation unit directly contains non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
- If namespaces imported by using namespace directives in the given namespace or compilation unit directly contain non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
- If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
- Otherwise, overload resolution is applied to the candidate set as described in (§7.5.3).
Which takes into general standard overload resolution territory.
Emphasis mine
7.5.3 Overload resolution
Overload resolution is a binding-time mechanism for selecting the best function member to invoke given an argument list and a set of candidate function members. Overload resolution selects the function member to invoke in the following distinct contexts within C#:
...
- Given the set of applicable candidate function members, the best
function member in that set is located. If the set contains only one
function member, then that function member is the best function
member. Otherwise, the best function member is the one function member
that is better than all other function members with respect to the
given argument list, provided that each function member is compared to
all other function members using the rules in §7.5.3.2. If there is
not exactly one function member that is better than all other function
members, then the function member invocation is ambiguous and a
binding-time error occurs.
Which leads us to
Emphasis mine
7.5.3.2 Better function member
For the purposes of determining the better function member, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list.
...
• Otherwise, if MP has more specific parameter types than MQ, then MP
is better than MQ
The short of this is
DbSet actually implements IQueryable not IEnumerable
- The extension methods are in the same namespace
- Standard overload resolution principles are applied in this case
- Which constructs a candidate list of applicable function members.
- The better function member principles are applied.
This makes the IQueryable method (with the exact type) the better match
You can test it for your self
Given
public static class LobExtensions
{
public static void Test1(this ILob asd) { }
}
public static class BobExtensions
{
public static void Test1(this IBob asd) { }
}
public interface ILob { }
public interface IBob : ILob { }
public class Bob : IBob { }
Usage
var asd = new Bob();
asd.Test1();
Result being BobExtensions.Test1 will be the best match and the chosen method