using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.Collections.Generic;
public static void Main()
GenericReturnTypeIsNullable(typeof(Program).GetMethod("Foo")).Dump();
public static bool GenericReturnTypeIsNullable(MethodInfo methodInfo)
var nullableAttribute = methodInfo!.ReturnTypeCustomAttributes.GetCustomAttributes(true).FirstOrDefault(x => x.GetType().FullName == "System.Runtime.CompilerServices.NullableAttribute");
if (nullableAttribute != null)
var flagsField = nullableAttribute.GetType().GetField("NullableFlags");
var flags = (byte[]?)flagsField?.GetValue(nullableAttribute);
return flags != null && flags.Length >= 2 && flags[1] == 2;
if (CheckNullableContext(methodInfo.CustomAttributes))
for (var type = methodInfo.DeclaringType; type != null; type = type.DeclaringType)
if (CheckNullableContext(type.CustomAttributes))
static bool CheckNullableContext(IEnumerable<CustomAttributeData> customAttributes)
var context = customAttributes.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
return context != null &&
context.ConstructorArguments.Count == 1 &&
context.ConstructorArguments[0].ArgumentType == typeof(byte) &&
(byte)context.ConstructorArguments[0].Value! == 2;
public Task<string>? Foo() => Task.FromResult("Foo");