To illustrate my question I've written a simple method:
public static T ConvertTo<T>(...)
where T : ISomeInterface
{
// return an instance of T
}
Obviously this method can be called like
ConvertTo<ISomeInterface>(...)
But in my case it doesn't make sense. Method should return an instance of a class that implements ISomeInterface. At now I throw NotSupportedException for any type the method unable to work with and I satisfied with this solution. But if I could filter out an interface itself in compile time it would be better.
So my question is: Is it possible to constrain generic parameter with implementations of an interface?
So my question is: Is it possible to constrain generic parameter with implementations of an interface?
No, there is not. You have found the best-fitting solutions: class and new(), where class only filters out structs, etc. class and new() used together is the only real solution, but a solution that is actually too strict.
You might have some luck with code analyzers or AOP where can filter out bad calls on compile-time.
Related
I was browsing through Github when I noticed an interface in C# that had the following:
public interface IAction : IPrototype<IAction>
I have never seen this before. So I was curious what this exactly means or what it does and if this is applicable to things other than interfaces?
Is this a C# specific syntax for a specific behavior? (Is it useful in other OOP languages)
Sorry, if this is a really noob question but, I don't even know what this is called so I couldn't figure out exactly how to simply google it :P
That means that IAction inherits a generic IPrototype<T> interface where the type is IAction. IPrototype<T> may define a member to consume or produce a T, in this case it would be a IAction.
It's an interface that inherits from a generic interface.
To me this looks like an interface that enforces the prototype pattern by implementing the curiously recursive template pattern. More info can be found here https://zpbappi.com/curiously-recurring-template-pattern-in-csharp/.
Essentially, you are able to define an interface that contains methods that return or consume strongly typed instances of the implementor. Without the pattern the best you could do is return an instance of the base interface.
The prototype pattern is a pattern that allows for a class to be cloned, so I guess that the IPrototype interface has a method called Clone that returns T. In this case it would return IAction.
public interface IPrototype<T> where T : IPrototype<T>
{
// enforces a clone method returning the sub class
T Clone();
}
Consider the following classes and interfaces:
interface IFactory<T>{}
class Factory<T> : IFactory<T>{ }
interface IEntity{}
class Entity : IEntity{ }
I would like Autofac to resolve IFactory<IEntity> to Factory<Entity> like this:
b.RegisterType<Factory<Entity>>().As<IFactory<IEntity>>();
But I get the following exception (abbreviated for clarity):
The type 'Factory`1[Entity]' is not assignable to service 'IFactory`1[[IEntity]]'
Why is that and how can the issue be resolved? Or am I trying something "wrong"?
I briefly looked into RegisterGeneric, but I don't think it applies here; also, because the above is just an example. In other cases I may want to define a different component for IFactory<IEntity>.
This isn't an Autofac issue - it's a matter of generic variance. You'd see exactly the same in a simple C# program:
public class Program
{
public static void Main()
{
IFactory<IEntity> factory = new Factory<Entity>();
}
}
Most generic interfaces are invariant - the type arguments have to match exactly. Some are covariant like IEnumerable<T>, allowing you to write:
IEnumerable<object> objects = new List<string>();
and some are contravariant like IComparer<T>, allowing you to write:
IComparer<string> = Comparer<object>.Default;
Covariant interfaces only allow their type parameters to come "out" of the implementation (e.g. via return types). Contravariant interfaces only allow their type parameters to go "into" the implementation (e.g. via regular parameters). It gets subtle when you have delegate parameters that themselves accept values etc, but we'll ignore that for now...
It sounds like your IFactory<T> should be covariant - so you just change the declaration like this:
interface IFactory<out T>{}
At that point, the code compiles and I'd hope that Autofac can handle it too. That does require that your interface never uses T as an input though. (We can't tell as you haven't shown any interface members.)
For more details on generic variance, see the MS documentation.
I'm doing the following in my interface, reason being I don't want to be tightly coupled to the implementation of IEquipment in my implementations of IEquipmentDataProvider
public interface IEquipmentDataProvider
{
IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();
}
But I think that the type constraints should be left to the implementation and I should just declare IEquipment GetEquipment(string path); in my interface. However, if I do that it's an interface for a redundant method as that method will never get called.
Is it considered okay to implement type constraints in an interface method, or is there another pattern I should consider?
Edit:
The reason I'm doing this is because I don't want my data access layer to have to use a concrete implementation of IEquipment and I can leave that to the domain logic layer. Hence the use of the generics , which will be an instance of IEquipment but decided upon by dll. And called with
Equipment eq = da.GetEquipment<Equipment>("somepath"); // where eq is Iequipment, and da is IEquipmentDataProvider
But I think that the type constraints should be left to the implementation and I should just declare IEquipment GetEquipment(string path); in my interface.
While I can see what you mean, I do think it's relevant here. Ignoring your type constraints, your interface definition makes it painfully clear that this is intended to work with equipment:
IEquipmentDataProvider
GetEquipment()
Return type IEquipment
It's almost unavoidable that you'd want to limit the usable types to those that implement IEquipment.
Does the following make sense to you? Is this an intended use case?
public class StringProvider : IEquipmentDataProvider
{
//...
}
var provider = new StringProvider();
var equipment = provider.GetEquipment<string>(myPath);
I'm pretty sure that it doesn't. Because it doesn't make sense to use anything other than an IEquipment implementation.
I think the issue is bigger than you're currently discussing. I see some other minor inconsistencies:
You make a generic E type argument, yet your return value is of type IEquipment. Why? Why not make E the return type? Existing code such as IEquipment myEquipment = myProvider.GetEquipment() will still work without needing changes, and you have the optional benefit of returning a specific type should you ever need it.
I don't quite understand why the method is generic but the class/interface itself isn't. There are use cases for generic methods, but yours seems to fit a generic class/interface much better.
I want to further address the second bullet point. Your interface, when implemented, will ensure that every implementation can get every type of `IEquipment.
Compare this to the generic class version:
public interface IEquipmentDataProvider<E> where E : IEquipment, new()
{
E GetEquipment<E>(string Path);
}
Pretty much the same code. But now, you can implement these interfaces specifically or generically, however you want it:
public class HammerDataProvider : IEquipmentDataProvider<Hammer> {}
public class SawDataProvider : IEquipmentDataProvider<Saw> {}
public class AllEquipmentDataProvider : IEquipmentDataProvider<IEquipment> {}
Every implementation of IEquipmentDataProvider can choose to either limit itself to a specific type (Hammer, Saw), or it can handle every implementation of IEquipment.
Edit
This also allows you to combine multiple interfaces, which can be implemented separately in the same class:
public class HammerAndSawDataProvider : IEquipmentDataProvider<Hammer>, IEquipmentDataProvider<Saw> {}
Due to a lack of type distinction between the two interface methods, you'll need to rely on explicit interface implementation. Maybe not what you want.
If your interface method had had different signatures between different generic types (e.g. GetEquipment<E>(E myEquipment) ), then you could've avoided needing to use explicit interface implementation.
This may be one step too far for your requirements, but it does showcase that you get absolute control over which equipment can be handled by a specific provider.
To summarize
The type constraint seems to be a given, based on the naming that you've used for the class and method.
It would make little to no sense to ever use a type that deviates from the suggested type constraint.
If you're already using a generic type; you're better off having your return type be the generic type. At worst, it doesn't break anything. At best, it allows for better type safety and less hard casting (e.g. it removes the need for performing a cast in Hammer myHammer = (Hammer)provider.GetEquipment(myPath);).
More often than not, you'll want to use the generic parameter at the class/interface level. The main drawback of generic methods (without a generic class) is that you have to repeatedly define a type constraint for every submethod that is called in the toplevel method. Generic methods (without a generic class) are generally only really warranted in "toolkit" methods, as far as I can think of right now.
Pedantic: I would rename the generic parameter to TEquipment (or TE if you want to be terse). Type parameters are usually named in a way that e.g. TElement is read as "type of the Element". But this is a matter of style and naming convention.
In your code, you do adhere to the "interface names begin with I" convention. Generic types have a similar convention about beginning with T.
Response to OP's update
Edit: The reason I'm doing this is because I don't want my data access layer to have to use a concrete implementation of IEquipment and I can leave that to the domain logic layer. Hence the use of the generics , which will be an instance of IEquipment but decided upon by dll.
This somewhat reaffirms my assertion that you should use a generic class/interface, not just a generic method.
If one were to paraphrase this line of code,
IEquipment GetEquipment<E>(string Path) where E : IEquipment, new();
it would become "a GetEquipment generic method with a constraint of type IEquipment with an implementation that has a default constructor".
Instead, the design could simply be an explicit interface method
Equipment eInstance=new Equipment();
IEquipmentDataProvider iEInstance=(IEquipmentIEquipmentDataProvider )eInstance;
iEInstance=iEInstance.GetEquipment(path);
so that, even if you have another class implementing the GetEquipment method differently, you could simply call the right GetEquipment method of IEquipment by using the explicit interface method.
Edit: after the OP's edit
EquipmentDataProvider edp=new EquipmentDataProvider();
IEquipmentDataProvider da=(IEquipmentDataProvider)edp; // An explicit method invocation to ensure that the EquipmentataProvider's GetEquipment and not some other Equipment class' GetEquipment is called. This is what is the intent of the
Equipment eq = da.GetEquipment<Equipment>("somepath");
In Java I can easily write:
public interface MyInterface<T extends Object>
and then have a method which determine the T at runtime like:
public MyInterface<?> DetermineObjectAtRuntime()
But in C# where <?> is not available and I need to call the method with type; which means I need to know the type before hand.
Is it possible to return generics type from non-generic method?
If not, how can I work out the type to call such generic method if I have an object instance with that type?
For people who are not sure what this is for - I have a set of data structures which are using different enums as field indexers. All the messages extends from a common generic interface with that enum as type variable. Now I need to work out a method which deserialize all different types of messages from a byte[] array.
In C#, which does not have type erasure, there are several ways to work around not knowing a type argument at compile-time:
Non-generic subset: If it happens to be the case that the methods of MyInterface<T> that you need don't involve T, then you can extract that portion of the interface into a base interface and return the base interface instead.
Pro: No runtime type shenanigans.
Con: Modifies the type (moving methods to a new base interface), breaking binary compatibility.
Type checking wrapper: Make a RuntimeTypeCheckedMyInterface<T> class that implements MyInterface<object> by delegating to a MyInterface<T> after type checking. Have the method return a MyInterface<object>, created by wrapping the MyInterface<whatever> inside a RuntimeTypeCheckedMyInterface.
Pro: Works with any existing interface type, without modifying it.
Con: Introduces "does T=object really mean object, or does it mean unknown type"? ambiguity.
Manual type erasure: Make a variant of MyInterface<T> that doesn't have a T like MyInterfaceOfUnknownType. Make MyInterface<T> inherit from MyInterfaceOfUnknownType. Have your method return MyInterfaceOfUnknownType.
Pro: Acts basically identical to Java, with MyInterfaceOfUnknownType = MyInterface<?>.
Con: Pollutes MyInterface<T> with non-generic methods. When the methods differ only by return type you have to disambiguate with a name change. Modifies the type (breaking source and binary compatibility).
Screw the types: Have the method return object or dynamic. Cast conditionally and appropriately.
Pro: Initially easy to do.
Con: Harder to maintain.
"But in C# where '< ? >' is not available and I need to call the method with type; which means I need to know the type before hand."
You can use dynamic instead of <T> for example:
dynamic Foo (dynamic Input) {return Input;}
The compiler determines the type at runtime.
In C#, you can have generic methods:
class Foo<X>
{
public T DoSomethingFunky<T>( ... )
{
...
}
}
But there's no way to have a wildcard type — a big fail in C#. It would be very useful in a lot of situations where you that it is a Widget<T> but you don't care about the particulars of T.
For instance, WCF throws FaultException<T>, where the various flavors of T are service specific. There's no way to catch something like FaultException<*> without simply catching the base Exception class and using reflection to inspect the caught exception to see if it's an interesting T. This prevents handling service faults in a generic way.
I believe the reason is that a concrete generic class (Widget<int>) are not really subtypes of the generic class (Widget<T>) it "inherits" from. The generic class is simply used as a template to compile a new specific class.
The one thing you could do, is have your generic template (Widget<T>) inherit from a non-generic base class (Widget) and have your method return that:
class AbstractWidget { ... }
class Widget<T> : AbstractWidget { ... }
.
.
.
public Widget GetGeneric Widget()
{
/* flavor determinated at runtime */
}
It's incumbent upon the caller to decide what to do with its Widget.
Another way is to add an extension
public static class MyExtensions
{
public static T As<T>(this object obj)
{
return (T)obj;
}
}
the above will provide you a .As() method
Imagine the following two classes:
class A
{
public A()
{
}
}
class B : A
{
public B()
{
}
}
Is it possible for me to define A, or alternatively an interface, in a way that forces class B to have a parameterless constructor? Or, more generalized, a constructor (or static method) that is able to create an instance of type B with a given signature?
I do not want to restrict class B to only be constructible using that signature, but I want to be sure that class B can be constructed with this signature (be it parameterless, or specifying certain parameters).
To be clear: I am not searching for a solution that would require me to use Reflection or any other method to figure that out at runtime (I don't have a problem with it, but it would make the code less readable, and generally seems like a bad idea in this case).
Is there a way to accomplish this?
I wrote a blog post that goes more in-depth about what I am trying to achieve here
There is no interface or base type that you can apply to the type to ensure it has a parameterless constructor. The only context in which you can make such a contraint is generic constraints:
public static void Foo<T>()
where T : new() {}
In such a case the only types that can be used with Foo must have a parameterless constructor.
You can define factory for instantiating objects of type A (and derived types):
interface IFactory<T> where T : A
{
T Create(int i);
T Create(string s);
// and so on...
}
and require factory implementation, when you want to create an object.
This will make sure calling code in compile time, that it tries to create an object with the given set of parameters.
Of course, there's nothing preventing from NotImplementedException from concrete IFactory<T> implementation at run-time.
This is a followup, since I did a little bit of research and at least managed to come up with an answer that is somewhat satisfying.
So after digging around a while and trying to figure out how the built-in serialization/deserialization in C# works, I found out that C# has a method called GetUninitializedObject(). This method seems like a hack, since it just avoids calling the constructor of the object in the first place, but it at least gives me a way to accomplish what I originally wanted: Being able to deserialize an object of an arbitrary type. Using this, I am able to use methods on the uninitialized created objects (and forcing their implementation via an interface).
I find this to be fitting my needs, although it does not do what I originally wanted to, it allows me to implement a pattern that works for my purposes.
Best Regards