C # static function in interface

Is there a way to simulate a static function in an interface in C #?

I want to use it for a factory in which each object inherits the static "Create" function from ICreateAble and in the factory class you can call Factory.Create(Type t, string fromFile ), which calls t.Create()

+6
c # directx
source share
5 answers

before “answering”, I want to state that you should fix the problem from your solution when asking questions, as you will probably get an answer that solves your solution, even if this is not the best way to solve your underlying problem.

If you really generalized the creation of objects, I would think about reversing this pattern a bit and using common ones to solve problems, rather than looking for a means to simulate a static method on an interface. This will require, of course, a rethinking of the solution.

Depending on the nature of the object (state or behavior), I would also like to separate creation from implementation. This is especially true if the object is a state object.

I will need to see more of what you are doing, but I assume that you have an abstract factory that calls Create (), which serves as a concrete factory ... inside the static method on the object that is being created. I am not sure, with additional context, that this is a good model. And I tend to NO.

0
source share

This question has been asked dozens of times, and usually the answer is no, ranging from "you cannot" to "you should not", or "it does not make sense." Many capable developers here on SO and on various blogs, etc., Went a lot to explain why this feature is not suitable for C #.

But the bottom line has valid use cases for static interfaces - I often use them in PHP, and of course there is a way to achieve something similar in C #. You do not need to think or hack, you just need to tweak your thinking a little.

First of all, think what exactly means “static”:

 public static class Foo { static Foo() { Value = "test"; } public static string Value { get; set; } } 

In a sense, the Foo class is just a global singleton object with the Bar property. This object is automatically created for you at startup, and you cannot create more than one instance, but otherwise it is functionally equivalent to the following non-stationary class:

 public class Bar { public Bar() { Value = "test"; } public string Value { get; set; } } 

It is necessary to use a different syntax for the constructor, and access to properties and method calls look different, but if you decide to save only one global instance of this object, and you decide to create this instance at startup, functionally, there is no difference.

The goal of this is to prepare you for the next idea: your types do not have to be static.

The reason you need an interface function is because you need to specify a “contract” to which your types should correspond, but interfaces do not work for you, because they determine how objects should correspond.

My answer to this question is simply to implement your types as concrete objects and store them statically - instead of relying on a “static” keyword for the part of your type that must match the interface.

For example, consider the Animal type with the Cat and Dog subtypes - and assume that all animals of a certain type produce the same sound, say that our animal types must provide sound. As you already know, the following does not work:

 public abstract class Animal { public static abstract string Sound { get; } } public class Cat : Animal { public static string Sound { get { return "Mee-oww."; } } } public class Dog : Animal { public static string Sound { get { return "Woof!"; } } } public void Test() { Animal cat = new Cat(); Animal dog = new Dog(); Assert.AreEqual(cat.GetType().Sound, Cat.Sound); Assert.AreEqual(dog.GetType().Sound, Dog.Sound); } 

Besides the fact that static abstract not supported, another serious problem with the test is that cat.GetType() returns a System.Type , which is a reflection of the type definition itself, and not a reference to a global static object that will be automatically created at startup. Since there is no syntax for abstract static methods, it follows that there is also no syntax for statically invoking an implementation of such a method.

The only way to access the static sound property is to directly refer to the type, for example. Cat.Sound or Dog.Sound . Okay, so this is not entirely true - you can access methods using reflection, but it probably won't be very convenient. Of course, you can also add another non-static property in each type of Animal for each property of the parent class, which explicitly refers to static properties. Again, I don't think this is a very convenient approach if you have many kinds of animals ...

Start over.

Forget about trying to use static properties and standard typing to achieve what you want - instead, add a specific type that defines what we define as an animal type:

 public class AnimalType { public AnimalType(string sound) { Sound = sound; } public string Sound { get; private set; } } 

Since System.GetType() only works for system types, we need a similar tool for Animal types, and we will leave this unrealized - forcing each specific Animal type to ensure that:

 public abstract class Animal { public abstract AnimalType AnimalType { get; } } 

Now we can implement specific types of animals - because we want one AnimalType to accompany each system type that extends the Animal class, we will define and store an instance of AnimalType in a static field inside each type - and our implementation of the AnimalType property will return this static instance:

 public class Dog : Animal { public static readonly AnimalType Type = new AnimalType(sound: "Woof!"); override public AnimalType AnimalType { get { return Type; } } } public class Cat : Animal { public static readonly AnimalType Type = new AnimalType(sound: "Mee-oww."); override public AnimalType AnimalType { get { return Type; } } } 

Now we can write a working test:

 public void StaticMethodInterface() { Animal dog = new Dog(); Animal cat = new Cat(); Assert.AreEqual(dog.AnimalType.Sound, Dog.Type.Sound); Assert.AreEqual(cat.AnimalType.Sound, Cat.Type.Sound); } 

The missing part is a tool that allows us to work with Animal types when all we have is System.Type but not the actual instance. In other words, we know the type of Animal, and we need access to it AnimalType. I came up with several solutions for this, some of which are related to reflection, some of which require an empty constructor in animal types. My favorite solution is to add a simple registry that maps to each Animal system type corresponding to AnimalType:

 public class AnimalType { public AnimalType(string sound) { Sound = sound; } public string Sound { get; private set; } private static IDictionary<Type, AnimalType> _types = new Dictionary<Type, AnimalType>(); public static void Register(Type type, AnimalType animalType) { _types.Add(type, animalType); } public static AnimalType Get(Type type) { return _types[type]; } } 

I believe that the safest way to populate this registry is to add static constructors to each system type of Animal, for example:

 public class Dog : Animal { public static readonly AnimalType Type = new AnimalType(sound: "Woof!"); static Dog() { AnimalType.Register(typeof(Dog), Type); } override public AnimalType AnimalType { get { return Type; } } } public class Cat : Animal { public static readonly AnimalType Type = new AnimalType(sound: "Mee-oww."); static Cat() { AnimalType.Register(typeof(Cat), Type); } override public AnimalType AnimalType { get { return Type; } } } 

This requires a little discipline at your end, like anything related to tasks related to runtime. I believe that this extra bit of work is preferable to using reflection or empty constructors to populate the registry.

Finally, we can add a test that demonstrates how to use System.Type to get AnimalType if we don't have an instance:

 public void Test() { var dogType = typeof (Dog); var catType = typeof (Cat); Assert.AreEqual(Dog.Type.Sound, AnimalType.Get(dogType).Sound); Assert.AreEqual(Cat.Type.Sound, AnimalType.Get(catType).Sound); } 

Finally, here is a complete example and test:

 public class AnimalType { public AnimalType(string sound) { Sound = sound; } public string Sound { get; private set; } private static IDictionary<Type, AnimalType> _types = new Dictionary<Type, AnimalType>(); public static void Register(Type type, AnimalType animalType) { _types.Add(type, animalType); } public static AnimalType Get(Type type) { return _types[type]; } } public abstract class Animal { public abstract AnimalType AnimalType { get; } } public class Dog : Animal { public static readonly AnimalType Type = new AnimalType(sound: "Woof!"); static Dog() { AnimalType.Register(typeof(Dog), Type); } override public AnimalType AnimalType { get { return Type; } } } public class Cat : Animal { public static readonly AnimalType Type = new AnimalType(sound: "Mee-oww."); static Cat() { AnimalType.Register(typeof(Cat), Type); } override public AnimalType AnimalType { get { return Type; } } } public void Test() { Animal dog = new Dog(); Animal cat = new Cat(); Assert.AreEqual(dog.AnimalType.Sound, Dog.Type.Sound); Assert.AreEqual(cat.AnimalType.Sound, Cat.Type.Sound); var dogType = typeof (Dog); var catType = typeof (Cat); Assert.AreEqual(Dog.Type.Sound, AnimalType.Get(dogType).Sound); Assert.AreEqual(Cat.Type.Sound, AnimalType.Get(catType).Sound); } 

Note that in this simple step-by-step tutorial, I use one AnimalType and register an instance for each system type Animal. Suppose you need alternative implementations for different types of Animal - just declare AnimalType abstract (or turn it into an interface), and then add it to the specific CatType and DogType types by registering them.

Finally, take a moment to reflect on the fact that it is actually much more flexible than static interfaces - in a sense, you define your own meta type definition on your domain. The advantage is that you can freely model your meta types using inheritance and interfaces, just like you model any other type hierarchy.

I don't consider this a workaround - in a sense, static interfaces will simply be the new syntax for something that you can already do better. By modeling your meta-types in the form of specific system types, you get a more user-friendly code base that will scale to meet new requirements without reprofiling in harsh conditions; you just extend your meta types just like other types.

Just adding static interfaces will not give you that degree of flexibility.

+5
source share
+1
source share

Your ICreateAble seems to be a factory class. The usual template is a separate factory class: you can define IWhatnot and IWhatnotFactory. If I implement IWhatnot, I would write a factory class that also implements IWhatnotFactory.

A faster and messier way would be to add a factory class method to IWhatnot and instantiate the instance otherwise that would be used (MyWhatnot, say), and use it as a factory class. It will be closer to what you are talking about. The difference is that there is an object you can refer to: the collection of the factory class is a collection of references to IWhatnot, and not to IWhatnotFactory. However, in any of these cases, you have a bunch of links to the interface, and each link refers to an instance of the class.

This is a special case of a broader question: Why does C # have no static virtual methods?

The reason is that classes are not really first-class objects in C #, and not in a way that would be useful here. An IW type reference does not refer to an instance of what IWhatnot implements. There is no equivalent for class reference. In C #, you can have a link to "any instance of a class that matches this description." You may not refer to “any CLASS that matches this description” - other than using reflection, as you suggest. But a method that can only be called through reflection will still be used as a language function.

The factory class template gives you a first-class object that creates an instance - you can think of it as a workaround so as not to use first-class classes as factories for your own instances.

It would be great if you could, but it would be a greater function than it seems at first glance. This is probably much more than I understand, since I could not cope with all the consequences. Language design is fun.

UPDATE

What you can do is collapse your own: query types for the static method of the given name and prototype. You cannot force the compiler to ensure its execution, but you can document it in an error message at runtime.

However, for ease of maintenance, I would recommend a factory class template rather than some exotic new way to do the same.

+1
source share

You cannot declare static methods on an interface because that is not what the interfaces are for.

Your best way of doing this is to create your own interface for everything you want to implement for your class, and then create the abstract / base class that you want your factory to inherit from. Your base class may have the static methods you want.

0
source share

All Articles