interface and generics C# - c#

I have a interface like this:
public interface IMyInterface<T> where T:class
{
long OS { get; set; }
T App { get; set; }
}
and another interface like this:
public interface IMyInterfaces
{
List<IMyInterface<T>> Subscribers { get; set; } //this line give me error
}
I got error

You need to specify a concrete type or another generic parameter for T when you use IMyInterface<T>
public interface IMyInterfaces
{
List<IMyInterface<int>> Subscribers { get; set; }
}
OR
public interface IMyInterfaces<TOther>
{
List<IMyInterface<TOther>> Subscribers { get; set; }
}
Note I used TOther to stress that it is another generic parameter, different from the T in IMyInterface but you could use the same name (T) for TOther

Related

Generic interfaces and inheritance in .NET

I have the following scenario that involves a couple of interfaces as below
internal interface ITranslation
{
string LanguageCode { get; set; }
string Title { get; set; }
}
Any object that hold translations will implement the ITranslation interface. Some of these objects can have synonyms as well, so I have another interface
internal interface ITranslationWithSynonmys : ITranslation
{
IList<string> Synonyms { get; set; }
}
Next step I have defined ITranslatable<T> interface for any object that has translations and can be translated in different languages
internal interface ITranslatable<T> where T : ITranslation
{
IList<T> Translations { get; set; }
}
while when there are synonyms involved the ITranslatableWithSynonyms<T> looks like this
internal interface ITranslatableWithSynonyms<T> : ITranslatable<T> where T : ITranslationWithSynonmys
{
IList<T> SynonymTanslations { get; set; }
}
Concrete implementations of ITranslation and ITranslationWithSynonmys would be
internal class BaseTranslation : ITranslation
{
public string Title { get; set; }
public string LanguageCode { get; set; }
}
internal class BaseTranslationWithSynonmys : ITranslationWithSynonmys
{
public IList<string> Synonyms { get; set; }
public string LanguageCode { get; set; }
public string Title { get; set; }
}
while an entity that can be translated would be
internal class TranslatableEntity : ITranslatable<ITranslation>
{
public IList<ITranslation> Translations { get; set; }
}
and if it has synomys
internal class TranslatableWithSynonymsEntity : ITranslatableWithSynonyms<ITranslationWithSynonmys>
{
public IList<ITranslationWithSynonmys> SynonymTanslations { get; set; }
public IList<ITranslationWithSynonmys> Translations { get; set; }
}
Next, I'm creating a service that can translate any object that implements ITranslatable<T> and I have defined it as
internal class TranslationService
{
internal string Translate(ITranslatable<ITranslation> translatable, string languageCode)
{
// It will iterate through the Translations list to find the correct translation
return string.Empty;
}
}
Now, when I try to use the service, I'm writting
var translationService = new TranslationService();
var translatableEntity = new TranslatableEntity();
var translatableWithSynonymsEntity = new TranslatableWithSynonymsEntity();
string x = translationService.Translate(translatableEntity, "en");
string y = translationService.Translate(translatableWithSynonymsEntity, "en");
and here the last line translationService.Translate(translatableWithSynonymsEntity, "en") fails to compile with error CS1503: Argument 1: cannot convert from 'TestInheritance.TranslatableWithSynonymsEntity' to 'TestInheritance.ITranslatable<TestInheritance.ITranslation>'
It's true that TranslatableWithSynonymsEntity doesn't implement ITranslatable<ITranslation>, but it implements ITranslatableWithSynonyms<ITranslationWithSynonmys> with both ITranslatableWithSynonyms<T> inheriting from ITranslatable<T> and ITranslationWithSynonmys inheriting from ITranslation.
I can get the code to compile by having TranslatableWithSynonymsEntity implement both ITranslatableWithSynonyms<ITranslationWithSynonmys> and ITranslatable<ITranslation>, but that means managing two lists and it doesn't look clean.
internal class TranslatableWithSynonymsEntity : ITranslatableWithSynonyms<ITranslationWithSynonmys>, ITranslatable<ITranslation>
{
public IList<ITranslationWithSynonmys> SynonymTanslations { get; set; }
public IList<ITranslationWithSynonmys> Translations { get; set; }
IList<ITranslation> ITranslatable<ITranslation>.Translations { get; set; }
}
Is there a way to avoid this? Or am I taking a wrong approach?
Thank you
Generic parameters are invariant by default, in the method Translate you want the type to be <ITranslation>, so you must provide a type whose (or its parents') generic parameter is exactly <ITranslation>.
In your example you cannot simply mark the parameter as covariant because it contains a property has both getter and setter.
Since the problem is the generic parameter, to solve the problem, don't specify one, in fact you have already constrained the generic parameter.
interface ITranslatable<T> where T : ITranslation
The method (or the class) just need to be declared with the same constraint.
internal string Translate<T>(ITranslatable<T> translatable, string languageCode)
where T : ITranslation

How to use an interface in an interface

I want to create an interface which can handle multiple other object of one interface.
I tried using the interface in the interface and using an object in the new class.
public interface IObject
{
double Value { get; set; }
}
public class FirstObject: IObject
{
double Value { get; set; }
}
public class SecondObject: IObject
{
string Titel { get; set; }
double Value { get; set; }
}
public interface ICollection
{
IObject[] Values { get; set; }
}
public class Collection: ICollection
{
SecondObject[] Values { get; set; }
}
Now I get the error, that my Collection doesn't implement the IObject[] Values member.
I thought when I use an object (SecondObject) which is implementing from the interface IObject the Collection should handle this.
What am I doing wrong and how can I solve this?
You might be off better here using generics:
public interface ICollection<T> where T : IObject
{
T[] Values { get; set; }
}
public class Collection : ICollection<SecondObject>
{
public SecondObject[] Values { get; set; }
}
The reason that it doesn't work now, is that the signature should match exactly. That means the Values should be an array of IObject, which it isn't. Using generics you can solve this, while keeping the type constraint.
A second, but inadvisable solution would be using an explicit interface implementation:
public SecondObject[] Values { get; set; }
IObject[] ICollection.Values
{
get
{
return this.Values;
}
set
{
this.Values = value?.Cast<SecondObject>().ToArray();
}
}

create an interface and its generic version

I want to create an interface and support its generic version and I'm not going to create two separate interface.
public interface IVMBase
{
string ParentPropertyName { get; }
string ParentForeignKeyPropertyName { get; }
string ChildsPropertyName { get; }
bool EnableChangeParent { get; set; }
RelayCommand<ChangeHierarchyParentArgs<Entity>> ChangeEntityParent { get; set; }
}
public interface IVMBase<T> : IVMBase where T : Entity
{
new RelayCommand<ChangeHierarchyParentArgs<T>> ChangeEntityParent { get; set; }
}
public abstract class VM<T> : IVMBase<T> where T : Entity
{
public RelayCommand<ChangeHierarchyParentArgs<T>> ChangeEntityParent { get; set; }
}
Compiler force me to implement two property for none-generic version of interface and its generic version and I dont want it.
Tanks a lot
Interfaces are a contract enforced by the runtime and the compiler - you can't make an exception just for yourself.
The behavior of your two ChangeEntityParent properties will be different in the generic and non-generic versions, but you can implement it using explicit interface implementation:
class Implementation<T> : IVMBase<T>
where T : Entit
{
// "explicit implementation" of the IVMBase property:
RelayCommand<ChangeHierarchyParentArgs<Entity>> IVMBase.ChangeEntityParent
{
get { ... }
set { ... }
}
// normal implementation of the IVMBase<T> property:
public RelayCommand<ChangeHierarchyParentArgs<T>> ChangeEntityParent
{
get { ... }
set { ... }
}
}
Using explicit-interface implementation allows types to have multiple members with the same name.

How do I reference a parent from a child object with generic interfaces in C#?

I have the following interface declarations:
interface IOrder<T> where T: IOrderItem
{
IList<T> Items { get; set; }
}
interface IOrderItem
{
IOrder<IOrderItem> Parent { get; set; } // What do I put here?
}
I want the items in the list to have a reference to the header object, so it can use the ID and other fields from the header.
In my concrete classes, it complains that I don't implement "Parent" properly.
class StoreOrder : IOrder<StoreOrderItem>
{
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem : IOrderItem
{
public StoreOrder Parent { get; set; } // This doesn't satisfy the interface
}
I tried setting up IOrderItem as IOrderItem<T> and passing in the Parent type, but that lead to circular reference since the Header class requries the Item class type... I got confused.
Any advice on how to implement this properly?
If you define your interfaces like so:
interface IOrder<T> where T : IOrderItem<T>
{
IList<T> Items { get; set; }
}
interface IOrderItem<T> where T : IOrderItem<T>
{
IOrder<T> Parent { get; set; }
}
You can then implement them like this to get the functionality that you expect:
class StoreOrder : IOrder<StoreOrderItem>
{
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem: IOrderItem<StoreOrderItem>
{
public IOrder<StoreOrderItem> Parent { get; set; }
}
class StoreOrder : IOrder<StoreOrderItem>
{
public int Id { get; set; }
}
class StoreOrderItem : IOrderItem
{
public IOrder<IOrderItem> Parent { get; set; } // This doesn't satisfy the interface
}
You may not specialize - IOrder<IOrderItem> is more general than StoreOrder
Here's a solution for changing the interfaces:
interface IOrder<TOrder, TOrderItem>
where TOrderItem : IOrderItem<TOrder>
{
IList<TOrderItem> Items { get; set; }
}
interface IOrderItem<TOrder>
{
TOrder Parent { get; set; }
}
Making changes to StoreOrder and StoreOrderItem to support the interface changes AND adding a couple properties to each for a later test:
class StoreOrder: IOrder<StoreOrder, StoreOrderItem>
{
public DateTime Date { get; set; }
public IList<StoreOrderItem> Items { get; set; }
}
class StoreOrderItem : IOrderItem<StoreOrder>
{
public string ItemName { get; set; }
public decimal ItemPrice { get; set; }
public StoreOrder Parent { get; set; }
}
...and now creating StoreOrder and StoreOrderItem instances, and putting them through their paces:
void Main()
{
var so = new StoreOrder { Date = DateTime.Now };
var item = new StoreOrderItem {
Parent = so,
ItemName = "Hand soap",
ItemPrice = 2.50m };
so.Items = new [] { item };
Console.WriteLine(item.Parent.Date);
Console.WriteLine(so.Items.First().ItemName);
}
...when run, printed:
3/16/2012 10:43:55 AM
Hand soap
Another option is to scrap the above and take this solution and alter it by adding the Parent property with the desired type and using explicit interface implementation to avoid casting at the call-sites, making for a StoreOrderItem implementation something like this:
class StoreOrderItem : IOrderItem
{
public string ItemName { get; set; }
public decimal ItemPrice { get; set; }
public StoreOrder Parent { get; set; } // note: original implementation
IOrder<IOrderItem> IOrderItem.Parent { // explicit interface implementation
get { return (IOrder<IOrderItem>)this.Parent; }
set { this.Parent = (StoreOrder)value; }
}
}
My favorite of the above is the first proposal above with the two-generic parameters to IOrder and the unconstrained generic-parameter on IOrderItem. A previous version I had posted and have now edited had both interfaces each with the same two generic types each with the same constraints. I felt like this was going a bit overboard so I pared it back to the above implementation. Although there is a complete lack of constraints on TOrder type parameter to IOrderItem - attempts to fudge other types in its place (e.g., object) resulted in compile errors. Using TOrder instead of just calling it T provides a hint about the expected type in the absence of the type constraint. That will be my final edit - I feel it is the most succinct of my attempts; if you are curious I can provide the former implementation that had the double-generic-constrained-types on the interfaces, but this is at least my preferred this solution. cheers!
Declaration to satisfy the interfaces:
class StoreOrder : IOrder<StoreOrderItem>
{
// interface members
public IList<StoreOrderItem> Items { get; set; }
// own members
public int Id { get; set; }
}
class StoreOrderItem : IOrderItem
{
public IOrder<IOrderItem> Parent { get; set; }
}
To access custom members you will have to cast:
class StoreOrderItem : IOrderItem
{
void Test()
{
int id = ((StoreOrder)this.Parent).ID;
}
}

When implementing an interface which define a base class property why can't the class implementing interface return a derived class type object?

Lets create some interfaces
public interface ITimeEventHandler
{
string Open();
}
public interface IJobTimeEventHandler : ITimeEventHandler
{
string DeleteJob();
}
public interface IActivityTimeEventHandler : ITimeEventHandler
{
string DeleteActivity();
}
public interface ITimeEvent
{
ITimeEventHandler Handler { get; }
}
public interface IJobTimeEvent : ITimeEvent
{
int JobID { get; }
}
Create a class
public class JobTimeEvent : IJobTimeEvent
{
public int JobID
{
get; internal set;
}
public IJobTimeEventHandler Handler
{
get; internal set;
}
}
My question is .. when implementing an interface which define a base class property why cant the class implementing interface return a derived class type object ??
For ex in class JobTimeEvent, IJobtimeEvent needs a property of type ITimeEventHandler but why IJobTimeEventHandler type is not allowed which derived from ITimeEventHandler
This is a duplicate of
Why C# doesn't allow inheritance of return type when implementing an Interface
The feature you want is called "return type covariance", and it is a frequently requested feature in C#. It is not supported by the CLR and we have no plans to implement it in C#, sorry!
Edit: The following is equally valid for get/set properties, so the fact that you can't declare fields in an interface is not fundamental to the points I'm making.
In your case, ITimeEvent.Handler is a field, which means you could do the following:
ITimeEvent x = ...;
IJobTimeEventHandler handler = ...;
x.Handler = handler;
If x was assigned an object of (concrete) type JobTimeEvent, and JobTimeEvent.Handler was declared as a JobTimeEventHandler, the the assignment above would fail. This is an example of how contravariance is not a safe operation for assignment.
If instead you had the following:
interface ITimeEvent
{
IJobTimeEventHandler Handler { get; }
}
Then you could easily do this:
class JobTimeEvent : ITimeEvent
{
private JobTimeEventHandler _handler;
public IJobTimeEventHandler Handler { get { return _handler; } }
}
It can return a class of this type, but it must satisfy the contract of the ITimeEvent interface and return it saying it's of type ITimeEventHandler. Suggest you use a property of this type, with a backing field of the derived type.
If you want the fields you definded to really be properties you could do something like this...
public interface ITimeEvent
{
ITimeEventHandler Handler { get; set; }
}
public interface IJobTimeEvent : ITimeEvent
{
int JobID { get; set; }
}
public class JobTimeEvent : IJobTimeEvent
{
public JobTimeEvent()
{
//these are currently useless because they are the default values
this.JobID = 0;
this.Handler = null;
}
public int JobID { get; set; }
public ITimeEventHandler Handler { get; set; }
}
... if you are trying to do something different you will need to provide more details to your question.

Categories