Can I define / restrict a member as an implementation of two interfaces without generics?

The following code shows what I would like to do; that is, I would like to restrict anObject so that it can be used as a parameter for various methods using IInterfaceOne or IInterfaceTwo, where they are not inherited from another.

public interface IInterfaceOne { } public interface IInterfaceTwo { } public class Implementation : IInterfaceOne, IInterfaceTwo { } public interface IInterfaceOneAndTwo : IInterfaceOne, IInterfaceTwo { } public class UsingImplementation { IInterfaceOneAndTwo anObject = (IInterfaceOneAndTwo)(new Implementation()); //fails because Implementation doesnt acctually implement IInterfaceOneAndTwo } 

This example does not work, since IInterfaceOneAndTwo is its own interface, and the implementation does not implement it.

I know that if I used generics, I could limit them, but I wonder if there is a way to do this without generics?

Is it possible to say that anObject should implement IInterfaceOne and IInterfaceTwo without using IInterfaceOneAndTwo ?

+4
source share
5 answers

The "inbound" parameters of a universal class and the general parameters of a method can combine types, but there is no means for variables or fields to represent "composite" types. In addition, in order to pass an object to a generic type parameter that combines several constraints, the object must be passed to a type that actually implements all of these constraints. It can be tricky.

For example, suppose the classes Foo and Bar implement Intf1 and Intf2 . One wants to write a function AddToList<T>(thing as T) where T:Intf1,Intf2 . Such a function perfectly accepts objects such as Foo or Bar . Suppose, however, that we want to use such a function to add all objects to the same list (this can be a combination of Foo , Bar and any number of other types that are also implemented by Intf1 and Intf2 ), and then pass these objects to functions whose parameter is also limited to implement both Intf1 and Intf2 . You could apply any object that turned out to be Foo , and apply any object that turned out to Bar , but if other types are written that also handle Intf1 and Intf2 , it would be difficult to handle them.

You can solve the problem somewhat inconveniently without using Reflection or other similar tricks. Define the IActUpon<Base1, Base2> interface using the ActUpon<thingType>ActUpon(thingType thing) where thingType: Base1, Base2 . Implementations of such a method will be able to pass the thing parameter to other methods that require a general method parameter limited to Base1 and Base2 . The biggest difficulties with this approach are that you need to write separate code for each possible number of restrictions, and that in many places where you would use a lambda expression, you need to write an implementation of IActUpon... .

+1
source

Not like now. Only general limitations have this ability.

You can rewrite it to use generics:

 public class UsingImplementation<T> where T : IInterface1, IInterface2, new() { T anObject = new T(); void SomeMethod() { anObject.MethodFromInterface1(); } } 
+5
source

You can also have common methods, not just common classes.

 public void DoSomething<T>(T value) where T : IInterface1, IInterface2 { value.DoInterface1Things(); value.DoInterface2Things(); } 

Or

 public void DoSomething<T>() where T : IInterface1, IInterface2, new() { T anObject = new T(); } 
+2
source

You cannot do this in C # without generics, but there is an alternative solution to the problem without generics , which are not mentioned here and can fit for you. This style is often used in conjunction with the IoC principle. You can enter the same object twice. Let me change your sample a little ...

 public interface IInterfaceOne { void Hello(); } public interface IInterfaceTwo { void World(); } public class Implementation : IInterfaceOne, IInterfaceTwo { public void Hello() { }; public void World() { }; } public class UsingImplementation { private readonly IInterfaceOne one; private readonly IInterfaceTwo two; public UsingImplentation(IInterfaceOne one, IInterfaceTwo two) { this.one = one; this.two = two; } // do the stuff you want to do with an IInterfaceOne using field one public DoSomeThingWithOne() { one.Hello(); } // do the stuff you want to do with an IInterfaceTwo using field two public DoSomeThingWithTwo() { two.World(); } } 

Then you can connect everything like this:

 var oneAndTwo = new Implementation(); var a = new UsingImplementation(oneAndTwo, oneAndTwo); // operates on the first param (which is the same as the second) a.DoSomeThingWithOne(); // operates on the second param (which is the same as the first) a.DoSomeThingWithTwo(); 

Look for the principle of IoC (control inversion) and dependency injection, and you will find more solutions similar to this one.

Thus, you do not need to create an additional interface combining InterfaceOne and InterfaceTwo, two.

+2
source

If desired, then there should be a logical connection between IInterfaceOne and IInterfaceTwo, and the implementation class should implement a unified interface:

 class Implementation : IInterfaceOneAndTwo { ... } 

If this is not possible because it is not (all) your code, then you may have to rethink UseImplementation. It simply does not fit on an accessible surface.

+1
source

Source: https://habr.com/ru/post/1393407/


All Articles