Proposal: Support for static classes to implement interfaces #2619
Replies: 19 comments
-
IL does not have this ability. A virtual call requires an instance of a class through which the class vtable can be looked up. Without an instance there's no way to know what method to call. However, the language team is looking into features that would enable more functionality for interfaces potentially including static members. Check this out: There's a lot there but you might be interested in the section under "Static interface members". This is still quite early in design and it's hard to say what will be accomplished via compiler trickery or might require runtime changes. |
Beta Was this translation helpful? Give feedback.
-
I also completely fail to understand your code sample, and from it, why such a feature would be neccesary. You have a class - not a static class, a regular class - that implements an interface. And then you're trying to invoke an instance method as though it was static. Without using the interface anywhere at all. What are you actually trying to achieve?? |
Beta Was this translation helpful? Give feedback.
-
Sorry @yaakov-h I thought it was obvious having named the classes LittleEndian and Endianness.. fixed it for you |
Beta Was this translation helpful? Give feedback.
-
You're still not actually using |
Beta Was this translation helpful? Give feedback.
-
@gigajew The following tricky code could roughly solve your problem. using System.IO;
public class Program
{
public static void Main()
{
Write2<LittleEndian>();
Write2<BigEndian>();
}
static void Write2<T>()
where T : struct, Endianness
{
default(T).WriteUInt16(new MemoryStream(), (ushort)2);
}
}
public interface Endianness
{
void WriteUInt16(Stream stream, ushort value);
}
public struct LittleEndian : Endianness
{
public void WriteUInt16(Stream stream, ushort value)
{
stream.WriteByte((byte)(value & 0xff));
stream.WriteByte((byte)((value >> 8) & 0xff));
}
}
public struct BigEndian : Endianness
{
public void WriteUInt16(Stream stream, ushort value)
{
stream.WriteByte((byte)((value >> 8) & 0xff));
stream.WriteByte((byte)(value & 0xff));
}
} |
Beta Was this translation helpful? Give feedback.
-
... what problem? He has yet to actually state what his problem is. |
Beta Was this translation helpful? Give feedback.
-
The problem is I have to add a lot of overhead right now to be able to implement the same structure to two classes like an interface |
Beta Was this translation helpful? Give feedback.
-
I don't follow. Defining an interface and two classes is more overhead than defining just two classes. What problem does the interface in static classes solve exactly, and how would you even use it? You haven't yet addressed either if those points. |
Beta Was this translation helpful? Give feedback.
-
How do you not follow? I need two classes with the same methods defined. Both of them use the same methods. But they both use them different ways. None of them need disposed of so they don’t really need instances. What’s not to understand? |
Beta Was this translation helpful? Give feedback.
-
Right, so your problem is:
Is that correct? That's not obvious because you never stated that, and because interfaces normally exist so that you can use them to refer to a type without knowing what type implements the interface, which is not what you're using them for here. Normally when people ask for static interfaces, it's because they want to do something like this: public void Foo<T>() where T : Endianess
{
T.WriteUInt32(....);
} |
Beta Was this translation helpful? Give feedback.
-
It seems like you want an interface just to keep the two classes in sync with each-other, rather than actually using the interface to invoke methods. Is that correct? |
Beta Was this translation helpful? Give feedback.
-
It’s be for both reasons |
Beta Was this translation helpful? Give feedback.
-
There's no facility in the CLR to invoke a static method through an interface or through a generic type constraint. Both would require runtime changes. The "shapes" proposals seek to emulate that behavior by using a "witness" struct through which the "static" interface members would be implemented as instance members that delegate to the static member of the implementing type. But as far as I can tell "shapes" don't propose to impose a contract on the implementing type itself in that the compiler would actually require you to implement those static members. But those proposals are in the fairly early design stages so it's hard to say what they would require. Without CLR support I don't see how that could be done, especially when you take into consideration how that will work across languages. |
Beta Was this translation helpful? Give feedback.
-
I think this is a proper example for the OP proposal: interface ILog
{
void Log(string message);
}
static class ConsoleLogger : ILog
{
public static void Log(string message) { Console.WriteLine(message); }
}
// elsewhere
void Foo(ILog logger) { /* ... */ }
// invoke without instance
Foo(ConsoleLogger); Right now you need to do it like this: class ConsoleLogger : ILog
{
public void Log(string message) { Console.WriteLine(message); }
}
// do we need to allocate?
Foo(new ConsoleLogger());
// or switch to singleton impementation
Foo(ConsoleLogger.Instance); |
Beta Was this translation helpful? Give feedback.
-
Yes sir, that's it |
Beta Was this translation helpful? Give feedback.
-
interface ILog
{
void Log(string message);
}
static class ConsoleLogger
{
public static ILog Log { get; } = new ConsoleLoggerImpl();
private class ConsoleLoggerImpl : ILog {
public void Log(string message) => Console.WriteLine(message);
}
}
// elsewhere
void Foo(ILog logger) { /* ... */ }
// invoke with static implementation
Foo(ConsoleLogger.Log); |
Beta Was this translation helpful? Give feedback.
-
I want to point to the solution already proposed at #2619 (comment) . It solves your problem, though it does require a bit of boilerplate. We are considering features that would remove the boilerplate. |
Beta Was this translation helpful? Give feedback.
-
It's likely also worth calling out that .NET Core 2.1 and higher has |
Beta Was this translation helpful? Give feedback.
-
@gigajew Surely designing a robust singleton implementation will give you what you need? Since a singleton can only exist once and classes can readily implement interfaces your problem is solved is it not? Here's a (hastily) contrived example based on what's posted above. using System.IO;
public class Program
{
public static void Main()
{
Singleton<LittleEndian>.Instance.Write2();
Singleton<BigEndian>.Instance.Write2();
}
}
public interface Endianness
{
void Write2();
void WriteUInt16(Stream stream, ushort value);
}
public class LittleEndian : Endianness
{
public void Write2()
{
WriteUInt16(new MemoryStream(), (ushort)2);
}
public void WriteUInt16(Stream stream, ushort value)
{
stream.WriteByte((byte)(value & 0xff));
stream.WriteByte((byte)((value >> 8) & 0xff));
}
}
public class BigEndian : Endianness
{
public void Write2()
{
WriteUInt16(new MemoryStream(), (ushort)2);
}
public void WriteUInt16(Stream stream, ushort value)
{
stream.WriteByte((byte)((value >> 8) & 0xff));
stream.WriteByte((byte)(value & 0xff));
}
}
public static class Singleton<T> where T : new()
{
public static T Instance { get { return Nested.Instance; } }
private class Nested
{
static Nested()
{
Instance = new T();
}
internal static readonly T Instance;
}
} (I leveraged this article when putting this together). |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I have this issue where I need a static class to implement from an interface. Appearently the IL has support for it but C# compiler / language does not.
Beta Was this translation helpful? Give feedback.
All reactions