0

I have an assignment that I have to write a custom attribute. The attribute must be applicable to interfaces only (at most once) and allows me to associate the name (it must be a String) of the default implementation to its interface. (There can be even more than one implementation, but it's important that there must be at least one default implementation). The following is my code:

[AttributeUsage(AttributeTargets.Interface)]
public class ImplementationNameAttribute:Attribute
{
    public List<string> Implementations { get; set; }

    public ImplementationNameAttribute(List<string> implementations)
    {
        foreach(var i in implementations)
            Implementations.Add(i);

    }
}
[ImplementationName(/*what should I write here?*/)]
public interface I
{

}

public class C:I
{

}

If the parameters are string, how can I use GetType() to check if a certain object is indeed a class and is an implementation of interface I? Keep in mind that the assignment says the parameters are strings and not objects.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
tofana
  • 83
  • 1
  • 5
  • Where do you want to check this? At runtime? At compile time? Also, the implementation may be in another assembly which is not available at the time of checking. – Klaus Gütter Jul 04 '21 at 18:23

2 Answers2

1

You cannot pass a List<T> to an attribute, but you can pass it an array of strings.

With the list, the compiler generates a

CS0181 Attribute constructor parameter 'implementations' has type 'List', which is not a valid attribute parameter type

[AttributeUsage(AttributeTargets.Interface)]
public class ImplementationNameAttribute : Attribute
{
    public string[] Implementations { get; }

    public ImplementationNameAttribute(params string[] implementations)
    {
        Implementations = implementations;
    }
}
[ImplementationName("IA", "IB", "IC")]
public interface I
{
}

Without the params keyword you would have to write

[ImplementationName(new[] { "IA", "IB", "IC" })]

Of course, you could still keep the List<string> for the property and add it the elements from the string array parameter.


Testing the existence of these interfaces at compile time can be done with the nameof keyword. It simply returns a string constant for the identifier you pass it.

The identifier must correspond to an existent variable, type, namespace or member. nameof always only returns the last part of a qualified identifier. E.g., nameof(N.IA) returns "IA". If you need the full name you must write nameof(N) + "." + nameof(IA).

[ImplementationName(nameof(IA), nameof(IB), nameof(IC))]

nameof does of course not test whether you pass it a interface name or something else. Also, this approach works only if the type is known at compile time. If it is in an assembly loaded at runtime, things get tricky. See this answer to "Resolve Type from Class Name in a Different Assembly".

Type.GetType("typename", false) returns null if a type does not exist but does not throw an exception. You can use it to test whether the type exists.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
0

If the parameters are string, how can I use GetType() to check if a certain object is indeed a class and is an implementation of interface I? Keep in mind that the assignment says the parameters are strings and not objects.

To create an instance of System.Type from a string, use Type.GetType(stringQualifier). https://learn.microsoft.com/en-us/dotnet/api/system.type.gettype?view=net-5.0#system-type-gettype(system-string)

The assembly the type, qualified by the string, is located in, must be loaded when you do that. Also afaics it depends on the .NET Framework version how precisly the typename you pass in as string must be specified.
A fully qualified typename in .NET is not only the classname, but also the namespace and the assembly name incl the GUID, the language and the public key token. Maybe if interface and class are of the same assembly ("project" in VS), it's sufficient to specify the namespace and the classname.

Btw you can also use Reflection to find out which class implements which interface - without any attributes.

lidqy
  • 1,891
  • 1
  • 9
  • 11