I am working on a class library and am having some trouble with generics. I have a ITransaction interface which has a collection of ITransactionItem. Each ITranscation can be either a CapitalCall or Distribution. A CapitalCall is a ITransaction but has a few additional properties. A CapitalCallItem is a ITransactionItem with a few additional properties. A CapitalCall has a collection of CapitalCallItems. Likewise, there exists a Distribution class with a collection of DistributionItem.
I have tried making the Transaction interface generic:
interface ITransactionBase<TItem>
where TItem: ITransactionItem
{
List<TItem> ITransactionItems
{
get;
set;
}
}
This works perfectly when I implement it:
class CapitalCall : ITransactionBase<CapitalCallItem>
Now all of the items in the collection are of type CapitalCallItem.
I run into the following problem. I would like to know the associate ITransaction on a ITranscationItem. I created a property on the ITransactionItem table of type ITranscation. When I use this property, it is no longer typed to the correct class:
var capitalCall = new CapitalCall();
var trans = capitalCall.TransactionItems[0].Transaction;
// trans is now of the base type ITransaction, instead of typed to CapitalCall.
I have tried making the ITransactionLineItem interface use generics as well, but I get into a recursive generic nightmare when I try to declare it. What is the correct way to model this?
Would this work:
interface ITransaction<TAction, TItems>
where TItems : ITransactionItem<TAction, TItems>
where TAction : ITransaction<TAction, TItems>
interface ITransactionItem<TAction, TItems>
where TItems : ITransactionItem<TAction, TItems>
where TAction : ITransaction<TAction, TItems>
I am confused as to how I could then use the interface by itself- what if I want a collection of mixed ITransactionItem, without specifying a type? Also I should add that I have base Transaction / Transaction item classes that implement the interface, and CapitalCall / Dist inherit from.
Yes, this sort of mutually recursive generic declaration will work, but it will make things very complicated - I know from experience. If you want an example of something similar, look at this declaration from my protocol buffers port:
public interface IMessage<TMessage, TBuilder> : IMessage<TMessage>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>
IBuilder<,> has the equivalent.
This declaration also demonstrates the answer to your last question: if some parts of your interface don't need to know the exact type of transaction, you can declare them in a "less generic" base interface. So you could have:
interface ITransaction<TAction, TItems> : ITransaction
where TItems : ITransactionItem<TAction, TItems>
where TAction : ITransaction<TAction, TItems>
for example, where ITransaction is a non-generic interface.
Again though, this is not for the faint of heart. In my case I can get away with it because almost no-one uses the raw interfaces - all the implementations are autogenerated, and client code uses those non-generic implementations. I would think long and hard before inflicting this on a developer to actually use day to day...
Yes the interfaces you wrote down should work as far as I can tell. Such "recursive" declarations work well with generics, but the question is whether you really need to make those generic in the first place? Recursive declarations are something which is not often used and may therefore be hard to grasp for other people using your classes.
As for using the interface for itself, you can still make a less generic interface and also implement it.
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();
}
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");
I found the following implementation in a code base I am going through
Interface IOrder
{
GetSubmittedOrder();
CreateOrder();
GetExistingOrder();
}
Class Order : IOrder
{
BuildSpecialOrder();
AddSpecialOrderParameters();
IOrder.GetSubmittedOrder();
IOrder.CreateOrder();
IOrder.GetExistingOrder();
}
Now, when we want to access the last three methods from this Order object, we need to do the following declaration
IOrder objOrder = new Order();
What is the reason(advantages) for creating an implementation like this? Does this practice have a specific name?
Note: Please let me know if this is a better fit at programmers.
I would say that that's the incorrect usage of explicit interface implementation. It basically means that the methods are not visible in the public class contract. That's why you have to cast the object to the interface type first (you are using an implicit cast). You could also have done:
var order = (IOrder)order;
order.GetExistingOrder();
It's normally used when the class method collides with an interface method or when a class implements two interfaces with the same method (but different purposes).
It should be used with care since it can indicate that your class have a too large responsibility (and should be divided into smaller classes).
Its called explicit interface implementation.
It is used to differentiate the implementation of specific interface in case multiple interface are implemented have the colliding names of methods.
interface IOrder
{
GetSubmittedOrder();
CreateOrder();
GetExistingOrder();
}
interface ISpecificOrder
{
GetSubmittedOrder();
CreateOrder();
GetExistingOrder();
}
Class Order : IOrder, ISpecificOrder
{
BuildSpecialOrder();
AddSpecialOrderParameters();
IOrder.GetSubmittedOrder();
IOrder.CreateOrder();
IOrder.GetExistingOrder();
ISpecificOrder.GetSubmittedOrder();
ISpecificOrder.CreateOrder();
ISpecificOrder.GetExistingOrder();
}
Consider adapter pattern Wiki - Adapter pattern
When communicating with other application or part of app (and many other requirements), you dont want to bind the type as it will be decided on run time, you can use this type of object declaration. this will create the object of interface type but will allocate memory of required type(nested in switch case or returned by other function).
IOrder objOrder = new Order();
Another thing mentioned in question is about implicit and explicit implementation of interface. Both can be used in different scenario. You can find more details from google.
I would like to pass a generic interface to a function:
private I<T> CreateStubRepository<T, I >()
where I : aGenericBaseClass
So i was wondering if generic interfaces implement a base class or specific interface?
I know by using reflection you can test if it is a generic class but I dont see that helping me
Well. What's the point of forcing the usage of any interface? I really do not get it (or your question).
You should more likely do something like this:
public interface IMyRepository<T>
{
}
public class Repository<T> : IMyRepository<T>
{
}
private IMyRepository<TEntity> CreateStubRepository<TEntity>()
{
return new Repository<TEntity>();
}
var repos = CreateStubRepository<User>();
Update
thanks for your answer but thats not what I am asking. What I want to know is does a class that implements a generic interface have a base class or does it inherit from an interface? I dont want to force any interface its more a question of is the object passed generic
Classes do not inherit interfaces. They implement them. The different is subtle but important.
A class can only inherit another class. This means that if you do not specify that a class inherits from another it will still inherit from object. And that wont change no matter how many interfaces a class implement.
class MyClass : ICoolInterface // inherits object
class MyList : ArrayList, ISomeInterface // inherits ArrayList
class MyGenericList<T> : IList<T> // inherits object.
Generic or non-generic classes can implement or inherit from generic or non-generic interfaces and classes. The only limitation is that the full type of any interface/class implemented/inherited from must be discernible given the full type of the class doing the implementing or inheriting. For example, a Foo<Bar> might inherit from FooBase and implement IDisposable; a FnordDuffleBag might inherit from DuffleBag<Fnord> and implement IReachInto<Fnord>.
Thanks for all the comments I think i was going in the wrong direction, What I was hoping for was that when I applied to a class the framework would know that it inherited from a base class or interface of say aGenericItemBaseClass before it constructed the class at runtime.
Yes I know that I can create a generic class with type parameters and use that but thats not what I was asking (although you may have got that impression from my posting).
At runtime I know that when using reflection I can determine if a class is generic by calling : IsGenericType which returns true if a type is generic.
So what I wanted to know which may have been explained poorly is, when using template types is there anyway to determine if that type is a generic type? It appears the answer is No the IL interperates the class as generic not the compiler.
I am building a entity Repository and I have an interface, IIdentifiable<T>. So entities which are identified by Guids, for example, implement IIdentifiable<Guid> with public Guid Id { get; }. So far, so good.
I have an interface of IRepository<T, TIdentifier> where T : IIdentifiable<TIdentifier>.
It seems to me that the TIdentifier generic argument is redundant, because that already information is held in the generic argument of T. Is there any way I can have a cleaner implementation of IRepository, where I only have to specify T in my business code?
I'm after something like 'IRepository<T> where T : IIdentifiable<T.GenericArgs[0]>.
I doubt this is possible, but just thought I'd ask. Maybe the new C# 4 stuff has something for this this?
There's no constraint on T which requires it to be a generic. And there's nothing which prevents a class from implementing IIdentifiable<T1>, IIdentifiable<T2>, ... IIdentifiable<Tn>, so even some syntax saying "the first argument of the IIdentifiable'1 interface implemented by T" wouldn't be sufficient.
You could create an IIdentifiable that has object Id { get; } then have IIdentifiable<T> : IIDentifiable with a generic Id property.
Then you can reduce the number of generic arguments to 1 like so:
IRepository<T> where T : IIdentifiable
In practice you would then use IRepository<X> with X : IIdentifiable<Guid>
This assumes that your IRepository is mainly interested in the ability of T to have a key and isn't focused on the specific type of key.
You are asking to be able to specify a contraint, based on the assumption that type has already satisfied that contraint, putting the compiler into a logical paradox.
Also, your plan makes TIdentifier unknown within IRepository which, I assume it's going to need to know.