Skip to content

Adding support for open generic types in attributes - #103213

Closed
hez2010 wants to merge 9 commits into
dotnet:mainfrom
hez2010:open-generic-attrs
Closed

Adding support for open generic types in attributes#103213
hez2010 wants to merge 9 commits into
dotnet:mainfrom
hez2010:open-generic-attrs

Conversation

@hez2010

@hez2010 hez2010 commented Jun 9, 2024

Copy link
Copy Markdown
Contributor

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

jkotas commented Jun 12, 2024

Copy link
Copy Markdown
Member

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
@ericstj

ericstj commented Jul 22, 2024

Copy link
Copy Markdown
Member

Per @jkotas comment, closing this PR as it's not ready for merge.

@ericstj ericstj closed this Jul 22, 2024
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

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.

3 participants