Home > Blockchain >  Access abstract static interface member
Access abstract static interface member

Time:02-01

How do I get the implemented Name from FooImpl from either the interface IFoo or an instance object?

public interface IFoo {
    static abstract string Name { get; }
}

public class FooImpl : IFoo {
    public static string Name => "Foo";
}

I can't seem to get the Name value from these methods. Am I missing something? Note that I'd like to access the Name from any implementation of IFoo without knowing the implementation being used. As such, FooImpl.Name would compile and run, but it is not what I'm looking to do directly.

IFoo anImpl = new FooImpl();
Console.WriteLine(anImpl.Name); // [CS0176] Member 'IFoo.Name' cannot be accessed with an instance reference; qualify it with a type name instead

// I know this won't work
Console.WriteLine(IFoo.Name); // [CS8926] A static virtual or abstract interface member can be accessed only on a type parameter.

static string GetName<T>() where T : IFoo
{
    return T.Name;
}
// I know this won't work
Console.WriteLine(GetName<IFoo>()); // [CS8920] The interface 'IFoo' cannot be used as type argument. Static member 'IFoo.Name.get' does not have a most specific implementation in the interface.

static string GetName2<T>(T implementation) where T : IFoo
{
    return T.Name;
}
Console.WriteLine(GetName2(anImpl)); // [CS8920] The interface 'IFoo' cannot be used as type argument. Static member 'IFoo.Name.get' does not have a most specific implementation in the interface.

I'm not sure what else to try. This post is related but I don't see an answer other than reflection.

CodePudding user response:

Note that I'd like to access the Name from any implementation of IFoo without knowing the implementation being used

Yes, this is impossible (other then with reflection). Static abstract interface members as any other static members belong to type, not to instance so they can be retrieved only via type. You can use the solution from the linked answer or call the GetName "dynamically" i.e. typeof(...).GetMethod(nameof(....GetName)).MakeGenericMethod(anImpl.GetType()).Invoke(null, null).

Also you can wrap either of the approaches in some helper and store the processed types values into Dictionary<Type, string> (or ConcurrentDictionary) to mitigate the reflection cost. Or even prebuild the dictionary (depends on the use case).

There is another approach but it requires some changes to the type hierarchy. You combine curiously recurring template pattern with extra method and extra generic interface with default method implementation:

public interface IFoo {
    static abstract string Name { get; }
    public string GetName();
}
public interface IFoo<T>: IFoo where T:IFoo<T>
{
    string IFoo.GetName() => T.Name;
}

public class FooImpl : IFoo<FooImpl> {
    public static string Name => "Foo";
}

And usage:

IFoo anImpl = new FooImpl();
Console.WriteLine(anImpl.GetName());
  • Related