Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for open generic types in attributes #103213

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

hez2010
Copy link
Contributor

@hez2010 hez2010 commented Jun 9, 2024

Enable open generic types in attributes.

Passing generic context in S.P.CoreLib so that open generic types can be resolved.
Skip instantiating generic attribute type if any type parameter is not provided.

Language proposal: dotnet/csharplang#8198

Pseudo C# code:

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        Console.WriteLine("Type");
        var type = typeof(Foo<int>);
        foreach (var attr in type.GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Generic Type Parameter");
        foreach (var attr in type.GetGenericTypeDefinition().GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Method");
        var method = type.GetMethod("Bar").MakeGenericMethod(typeof(bool));
        foreach (var attr in method.GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Param");
        foreach (var param in method.GetParameters())
        {
            foreach (var attr in param.GetCustomAttributes())
            {
                Console.WriteLine(attr);
            }
        }
        Console.WriteLine("Generic Method Parameter");
        foreach (var genericParam in method.GetGenericMethodDefinition().GetGenericArguments())
        {
            foreach (var attr in genericParam.GetCustomAttributes())
            {
                Console.WriteLine(attr);
            }
        }
        Console.WriteLine("Property");
        var prop = type.GetProperty("Prop");
        foreach (var attr in prop.GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Property Getter");
        foreach (var attr in prop.GetGetMethod().GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Property Setter");
        foreach (var attr in prop.GetSetMethod().GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Field");
        var field = type.GetField("Field");
        foreach (var attr in field.GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Event");
        var eventInfo = type.GetEvent("Event");
        foreach (var attr in eventInfo.GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Event Adder");
        foreach (var attr in eventInfo.GetAddMethod().GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
        Console.WriteLine("Event Remover");
        foreach (var attr in eventInfo.GetRemoveMethod().GetCustomAttributes())
        {
            Console.WriteLine(attr);
        }
    }
}

[My<T, T>]
class Foo<[My<T, T>] T>
{
    [My<T, U>]
    public void Bar<[My<T, U>] U>([My<T, U>] T value)
    {
    }

    [My<T, T>]
    public int Prop { [My<T, T>] get; [My<T, T>] set; }
    
    [My<T, T>]
    public int Field;

    [My<T, T>]
    public event Action<int> Event { [My<T, T>] add { } [My<T, T>] remove { }}
}

class MyAttribute<T, U> : Attribute
{
    public T Value1 { get; } = default;
    public U Value2 { get; } = default;

    public override string ToString()
    {
        return typeof(MyAttribute<T, U>) + " " + Value1 + " " + Value2;
    }
}

IL for testing: il.txt

Output:

Type
MyAttribute`2[System.Int32,System.Int32] 0 0
Generic Type Parameter
// no output here as the generic context of generic args returned from `type.GetGenericTypeDefinition()` has been stripped
Method
MyAttribute`2[System.Int32,System.Boolean] 0 False
Param
MyAttribute`2[System.Int32,System.Boolean] 0 False
Generic Method Parameter
// no output here as the generic context of generic args returned from `method.GetGenericMethodDefinition().GetGenericArguments()` has been stripped
Property
MyAttribute`2[System.Int32,System.Int32] 0 0
Property Getter
MyAttribute`2[System.Int32,System.Int32] 0 0
System.Runtime.CompilerServices.CompilerGeneratedAttribute
Property Setter
MyAttribute`2[System.Int32,System.Int32] 0 0
System.Runtime.CompilerServices.CompilerGeneratedAttribute
Field
MyAttribute`2[System.Int32,System.Int32] 0 0
Event
MyAttribute`2[System.Int32,System.Int32] 0 0
Event Adder
MyAttribute`2[System.Int32,System.Int32] 0 0
Event Remover
MyAttribute`2[System.Int32,System.Int32] 0 0

Tests will be added later.

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jun 9, 2024
@jkotas
Copy link
Member

jkotas commented Jun 12, 2024

This is a partial prototype for a runtime support of a proposed C# language feature. There is not much to review. We should agree first that this is a C# language feature that we want to build.

@jkotas jkotas added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Reflection community-contribution Indicates that the PR has been added by a community member NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants