<#@ assembly name="System.Core" #> <#@ assembly name="System.Runtime" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Threading" #> <#@ import namespace="System.Threading.Tasks" #> <#@ import namespace="System.Collections.Generic" #> <# var infoFieldNames = new Dictionary(); var toQuotedImpl = default(Func); toQuotedImpl = (t, i, b) => { var name = t.Name; if (t.IsGenericType) { var genDef = t.GetGenericTypeDefinition(); name = genDef.Name.Substring(0, genDef.Name.LastIndexOf('`')); var genArgs = "<" + string.Join(", ", t.GetGenericArguments().Select(a => toQuotedImpl(a, i, false))) + ">"; if (b) { if (name == "Func" || name == "Action") { name = "Expression<" + name + genArgs + ">"; } else if (name == "IAsyncEnumerable" && i == 0) { name = "IAsyncQueryable" + genArgs; } else if (name == "IOrderedAsyncEnumerable" && i == 0) { name = "IOrderedAsyncQueryable" + genArgs; } else { name += genArgs; } } else { if (name == "Nullable") { name = genArgs.Substring(1, genArgs.Length - 2) + "?"; } else { name += genArgs; } } } else if (t.IsArray) { var elem = toQuotedImpl(t.GetElementType(), i, b); name = elem + "[]"; } else { if (t == typeof(int)) { name = "int"; } else if (t == typeof(long)) { name = "long"; } else if (t == typeof(float)) { name = "float"; } else if (t == typeof(double)) { name = "double"; } else if (t == typeof(decimal)) { name = "decimal"; } else if (t == typeof(bool)) { name = "bool"; } else if (t == typeof(object)) { name = "object"; } } return name; }; var toQuoted = new Func((t, i) => toQuotedImpl(t, i, true)); #> #nullable enable using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using System.Threading; using System.Threading.Tasks; namespace System.Linq { public static partial class <#=className#> { <# // NOTE: Just including extension methods foreach (var m in asyncEnumerableType.GetMethods() .Where(m => m.IsStatic) .Where(m => !exclude.Contains(m.Name)) .Where(m => m.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), true)) .Where(m => { var p0 = m.GetParameters()[0].ParameterType; if (p0.IsGenericType) { var p0d = p0.GetGenericTypeDefinition(); return p0d == typeof(IAsyncEnumerable<>) || p0d == typeof(IOrderedAsyncEnumerable<>); } return false; }) .OrderBy(m => m.Name) .ThenBy(m => m.IsGenericMethod ? m.GetGenericArguments().Length : 0) .ThenBy(m => m.GetParameters().Length) .ThenBy(m => string.Join(", ", m.GetParameters().Select((p, i) => toQuoted(p.ParameterType, i) + " " + p.Name)))) { var genArgs = m.GetGenericArguments(); var ret = toQuoted(m.ReturnType, 0); var name = m.Name; if (genArgs.Length > 0) { name += "<" + string.Join(", ", genArgs.Select(a => a.Name)) + ">"; } var isParams = false; var lastParameterDefault = false; var parCount = m.GetParameters().Length; if (parCount != 0) { var lastParam = m.GetParameters().Last(); if (lastParam.IsDefined(typeof(ParamArrayAttribute), true)) { isParams = true; } if (lastParam.ParameterType == typeof(CancellationToken)) { lastParameterDefault = true; } } var pars = string.Join(", ", m.GetParameters().Select((p, i) => (i == parCount - 1 && isParams ? "params " : "") + toQuoted(p.ParameterType, i) + (nullableParameterNames.Contains(p.Name) ? "?" : "") + " " + p.Name + (i == parCount - 1 && lastParameterDefault ? " = default" : ""))); var quotedPars = string.Join(", ", m.GetParameters().Select((p, i) => "default(" + toQuoted(p.ParameterType, i) + ")")); if (m.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), true)) { pars = "this " + pars; } var infoName = m.Name; var infoTypeArgs = ""; var infoToGeneric = ""; var infoMakeGeneric = ""; var infoGenArgs = ""; if (genArgs.Length > 0) { infoName += "__" + string.Join("_", genArgs.Select(a => a.Name)); infoTypeArgs = "(" + string.Join(", ", genArgs.Select(a => "Type " + a.Name)) + ")"; infoToGeneric = "!.GetGenericMethodDefinition()"; infoMakeGeneric = ".MakeGenericMethod(" + string.Join(", ", genArgs.Select(a => a.Name)) + ")"; infoGenArgs = "<" + string.Join(", ", genArgs.Select(_ => "object")) + ">"; } infoName += "__" + parCount + "__"; int infoNameCount; if (!infoFieldNames.TryGetValue(infoName, out infoNameCount)) { infoNameCount = 0; } var infoNameId = infoNameCount++; infoFieldNames[infoName] = infoNameCount; infoName += infoNameId; var infoSignature = string.Join(", ", m.GetParameters().Select((p, i) => toQuoted(p.ParameterType, i)).Concat(new[] { toQuoted(m.ReturnType, 0) })); foreach (var genArg in genArgs) { infoSignature = infoSignature.Replace(genArg.Name, "object"); } var mtd = infoName; if (m.IsGenericMethod) { mtd += "(" + string.Join(", ", genArgs.Select(a => "typeof(" + a.Name + ")")) + ")"; } var provider = m.GetParameters()[0].Name + ".Provider"; var factory = ""; var rem = ""; var cast = ""; var quotedArgs = new List(); if (m.ReturnType.IsGenericType) { var td = m.ReturnType.GetGenericTypeDefinition(); if (td.Name.EndsWith("Task`1")) // NB: Covers Task and ValueTask { factory = "ExecuteAsync<" + toQuotedImpl(m.ReturnType.GetGenericArguments()[0], -1, false) + ">"; var last = m.GetParameters().Last(); if (last.ParameterType == typeof(CancellationToken)) { rem = ", " + last.Name; } else { rem = ", CancellationToken.None"; } } else if (td == typeof(IAsyncEnumerable<>) || td == typeof(IOrderedAsyncEnumerable<>)) { factory = "CreateQuery<" + toQuotedImpl(m.ReturnType.GetGenericArguments()[0], -1, false) + ">"; if (td == typeof(IOrderedAsyncEnumerable<>)) { cast = "(" + toQuoted(m.ReturnType, 0) + ")"; } } } var n = 0; foreach (var p in m.GetParameters()) { var pt = p.ParameterType; var add = false; if (pt.IsGenericType) { var ptd = pt.GetGenericTypeDefinition(); if (ptd == typeof(IAsyncEnumerable<>) || ptd == typeof(IOrderedAsyncEnumerable<>)) { if (n == 0) { quotedArgs.Add(p.Name + ".Expression"); } else { quotedArgs.Add("GetSourceExpression(" + p.Name + ")"); } add = true; } else if (ptd.Name.StartsWith("Func") || ptd.Name.StartsWith("Action")) { quotedArgs.Add(p.Name); add = true; } } if (!add) { quotedArgs.Add("Expression.Constant(" + p.Name + ", typeof(" + toQuoted(pt, -1) + "))"); } n++; } var expr = "Expression.Call(" + mtd + ", " + string.Join(", ", quotedArgs) + ")"; var cons = name.StartsWith("ToDictionary") ? " where TKey : notnull" : ""; #> private static MethodInfo? s_<#=infoName#>; private static MethodInfo <#=infoName#><#=infoTypeArgs#> => (s_<#=infoName#> ?? (s_<#=infoName#> = new Func<<#=infoSignature#>>(<#=m.Name#><#=infoGenArgs#>).GetMethodInfo()<#=infoToGeneric#>))<#=infoMakeGeneric#>; public static <#=ret#> <#=name#>(<#=pars#>)<#=cons#> { <# var any = false; foreach (var p in m.GetParameters()) { if (!p.ParameterType.IsValueType && !p.ParameterType.IsGenericParameter && !nullableParameterNames.Contains(p.Name)) { any = true; #> if (<#=p.Name#> == null) throw new ArgumentNullException(nameof(<#=p.Name#>)); <# } } #> <# if (any) { #> <# } #> return <#=cast#><#=provider#>.<#=factory#>(<#=expr#><#=rem#>); } <# } #> } }