Implement an interface method with a concrete class - c#

I have the following interfaces, one for the entity and one for some logic:
public interface IItem
{
int Id { get; set; }
}
public interface IGenerator
{
IList<IItem> Generate();
}
and implementation:
public class ItemA : IItem
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ItemAGenerator : IGenerator
{
public IList<ItemA> Generate()
{
// do stuff
return List<ItemA>;
}
}
That implementation did not work, it says that it does not have the matching return type, so I also tried:
public class ItemAGenerator : IGenerator
{
public IList<IItem> Generate()
{
// do stuff
return List<ItemA>;
}
}
it does not work as well, it says: cannot implicitly convert type List<IItem> to List<ItemA>.
How to make it work? what am I missing here.

Just create the list as a List<IItem> but add ItemA's to it.
public class ItemAGenerator : IGenerator
{
public IList<IItem> Generate()
{
var list = new List<IItem>();
list.Add(new ItemA());
return list;
}
}

Just make IGenerator generic. Then you can specify the type that will be returned.
public interface IGenerator<T> where T : IItem
{
IList<T> Generate();
}
public class ItemAGenerator : IGenerator<ItemA>
{
public IList<ItemA> Generate()
{
// do stuff
return List<ItemA>;
}
}

Related

Cannot add a derived class object to a list of it's base class type

I have the following class structure:
//BaseClass
public abstract class BaseClass<T> where T : Model
{
public abstract T Data { get; set; }
public BaseClass(T data) { Data = data; }
}
public abstract class Model
{
public int Id { get; set; }
}
//ClassA
public class BaseClassA : BaseClass<ModelA>
{
public override ModelA Data { get; set; }
public BaseClassA(ModelA data) : base(data) { }
}
public class ModelA : Model { }
//ClassB
public class BaseClassB : BaseClass<ModelB>
{
public override ModelB Data { get; set; }
public BaseClassB(ModelB data) : base(data) { }
}
public class ModelB : Model { }
I would like to use them as follows:
List<BaseClass<Model>> myBaseList = new List<BaseClass<Model>>();
myBaseList.Add(new BaseClassA(new ModelA()));
myBaseList.Add(new BaseClassB(new ModelB()));
foreach (var item in myBaseList)
{
if (item.Data.Id > 0)
{
//do stuff
}
}
But I get the compiler exception:
cannot convert from BaseClassA to BaseClass<Model>
However, I was under the impresion that BaseClassA being of type BaseClass<ModelA> would be meet the requirement of being of type BaseClass<Model>.
For instance, this doesn't generate any errors:
List<Model> myModelList = new List<Model>();
myModelList.Add(new ModelA());
myModelList.Add(new ModelB());
I can't seem to wrap my head around where I went wrong with this.
One possible solution would be to introduce a covariant interface:
public interface IBase<out T> where T : Model
{
T Data { get; }
}
public abstract class BaseClass<T> : IBase<T> where T : Model
Then use the interface for your list:
var myBaseList = new List<IBase<Model>>();
myBaseList.Add(new BaseClassA(new ModelA()));
myBaseList.Add(new BaseClassB(new ModelB()));
Because IBase declares Data as get-only, this ensures type-safety.
And here you still have access to Data:
foreach (var item in myBaseList)
{
if (item.Data.Id > 0)
{
//do stuff
}
}

Generic type parameters C# - How to generic class return type

Suppose I have two classes and both contain the same fields
Class A
{
public string Name { get; set; }
public int Designaton { get; set; }
}
Class B
{
public string Name { get; set; }
public int Designation { get; set; }
}
And I have one interface and two classes which are inherited from interface
public interface IDeprt
{
object BindData();
}
And two extractor classes:
public classAItem : IDeprt
{
public object BindData()
{
return new A()
{
// mapping operation
}
}
}
public classBItem : IDeprt
{
public object BindData()
{
return new B()
{
//same mapping operation
}
}
}
My question, how can I implement this in generic way using <T> .
Both classes are doing same operation only return type change. If I am doing in the above way there is lot of duplication of code.
Make your ITem interface and also BindData generic make them use the same generic parameter.
public interface IItem<T>
{
T BindData();
}
Then implement the subclasses like below :
public class AItem : ITem<A>
{
public A BindData(){
return new A(){
// mapping operation
}
}
}
public class BItem : ITem<B>
{
public B BindData(){
return new B(){
//same mapping operation
}
}
}
Edit : As the question evolves.
Make a shared base class for A and B classes.
public abstract class CommonItem
{
public string Name { get; set; }
public int Designaton { get; set; }
}
class A : CommonItem
{
}
class B : CommonItem
{
}
Then make class with a method that accepts a generic parameter with new and CommonItem constraints.
public class Binder
{
public T BindData<T>() where T: CommonItem, new()
{
return new T()
{
// you can access the properties defined in ICommonItem
}
}
}
Usage :
var binder = new Binder();
var boundA = binder.BindData<A>();
var boundB = binder.BindData<B>();

generics interface constraint in c#

I've written a code as below. In this code I want to put a constraint on ServiceResult and BaseService classes so that T needs to implement IBaseEntity interface.
Here is the code:
public interface IBaseEntity
{
int Id { get; set; }
}
public class Photo : IBaseEntity
{
public int Id { get; set; }
public float FileSize { get; set; }
public string Url { get; set; }
}
public class ServiceResult<T> where T : class, IBaseEntity, new()
{
public bool Succeed { get; set; }
private T data;
public T Data
{
get
{
if (data == null)
data = new T();
return data;
}
set
{
data = value;
}
}
}
public abstract class BaseService<T> where T : class, IBaseEntity, new()
{
public abstract ServiceResult<List<T>> GetAll();
public abstract ServiceResult<T> GetById(int Id);
}
public class PhotoService : BaseService<Photo>
{
public override ServiceResult<List<Photo>> GetAll()
{
throw new Exception();
}
public override ServiceResult<Photo> GetById(int Id)
{
throw new Exception();
}
}
public class Program
{
public static void Main(string[] args)
{
Console.ReadKey();
}
}
In the code I get the error as below (error refers to GetAll() methods)
Error 3 The type
'System.Collections.Generic.List' cannot be used
as type parameter 'T' in the generic type or method
'FOC.Session04.ServiceResult'. There is no implicit reference
conversion from 'System.Collections.Generic.List'
to 'FOC.Session04.IBaseEntity'. G:\Courses\ASP.NET MVC5\Session4
960803\FOC.Session04\FOC.Session04\Program.cs 55 52 FOC.Session04`
But when I remove the interface constraint IBaseEntity from ServiceResult class and let it remain after BaseService I will get no error and the code compiles without error.
Can anybody explain me why I can't add constraint after ServiceResult class?
What's the reason? Or which part of code need to be changed in order to compile error less in this case?
Thanks all
I think you want rather
public abstract List<ServiceResult<T>> GetAll();
instead of
public abstract ServiceResult<List<T>> GetAll();
List<T> does not even match your constraints (hence the compiler error)
What you really need is for GetAll to return a List of ServiceResults, like so
public interface IBaseEntity
{
int Id { get; set; }
}
public class Photo : IBaseEntity
{
public int Id { get; set; }
public float FileSize { get; set; }
public string Url { get; set; }
}
public class ServiceResult<T> where T : class, IBaseEntity, new()
{
public bool Succeed { get; set; }
private T data;
public T Data
{
get
{
if (data == null)
data = new T();
return data;
}
set
{
data = value;
}
}
}
public abstract class BaseService<T> where T : class, IBaseEntity, new()
{
public abstract List<ServiceResult<T>> GetAll();
public abstract ServiceResult<T> GetById(int Id);
}
public class PhotoService : BaseService<Photo>
{
public override List<ServiceResult<Photo>> GetAll()
{
throw new Exception();
}
public override ServiceResult<Photo> GetById(int Id)
{
throw new Exception();
}
}
public class Program
{
public static void Main(string[] args)
{
Console.ReadKey();
}
}
I made a look at the source again and understood what is going on.
Putting IBaseEntity constraint on BaseService class has no problem. Because T represents a single class here (PhotoService : BaseService<Photo>). So T is Photo and Photo implements IBaseEntity.
But for GetAll() method in BaseService class the return type is ServiceResult<List<T>>. Therefore in ServiceResult class T will be something like List<Photo> and List<Photo> doesn't implement IBaseEntity. Therefore it raises an error.
Removing IBaseEntity constraint from ServiceResult class solves the problem.

Generic Abstract Class

I have the following code which is fine...
namespace GenericAbstract
{
public interface INotifModel
{
string Data { get; set; }
}
public interface INotif<T> where T: INotifModel
{
T Model { get; set; }
}
public interface INotifProcessor<in T> where T : INotif<INotifModel>
{
void Yell(T notif);
}
public class HelloWorldModel : INotifModel
{
public string Data { get; set; }
public HelloWorldModel()
{
Data = "Hello world!";
}
}
public class HelloWorldNotif : INotif<HelloWorldModel>
{
public HelloWorldModel Model { get; set; }
public HelloWorldNotif()
{
Model = new HelloWorldModel();
}
}
public class HelloWorldProcessor<T> : INotifProcessor<T> where T : INotif<INotifModel>
{
public void Yell(T notif)
{
throw new NotImplementedException();
}
}
}
As you can see there are 3 interfaces and each of those is implemented.
However, I would like the processor to be implemented like this:
public class HelloWorldProcessor : INotifProcessor<HelloWorldNotif<HelloWorldModel>>
{
public void Yell(HelloWorldNotif<HelloWorldModel> notif)
{
throw new NotImplementedException();
}
}
But i get the following error:
The non-generic type 'HelloWorldNotif' cannot be used with type arguments
I want the HelloWorldProcessor to implement INotifProcessor only for HelloWorldNotif...
Can't figure out what I am doing wrong..
For this to work you first have to make INotif<T> co-variant. That means that the Model property has to be read only for the interface (it can still have a public set in an implementation). Then to fix your immediate error you don't put the <HelloWorldModel> after HelloWorldNotif because it's already a INotif<HelloWorldModel>
public interface INotifModel
{
string Data { get; set; }
}
public interface INotif<out T> where T : INotifModel
{
T Model { get; }
}
public interface INotifProcessor<in T> where T : INotif<INotifModel>
{
void Yell(T notif);
}
public class HelloWorldModel : INotifModel
{
public string Data { get; set; }
public HelloWorldModel()
{
Data = "Hello world!";
}
}
public class HelloWorldNotif : INotif<HelloWorldModel>
{
public HelloWorldModel Model { get; set; }
public HelloWorldNotif()
{
Model = new HelloWorldModel();
}
}
public class HelloWorldProcessor<T> : INotifProcessor<T> where T : INotif<INotifModel>
{
public void Yell(T notif)
{
throw new NotImplementedException();
}
}
public class HelloWorldProcessor : INotifProcessor<HelloWorldNotif>
{
public void Yell(HelloWorldNotif notif)
{
throw new NotImplementedException();
}
}
Then I guess your implementation would be something like
Console.WriteLine(notif.Model.Data);
As others have said and/or implied out you've already got HelloWorldNotif fully specified. So to translate this:
I want the HelloWorldProcessor to implement INotifProcessor only for
HelloWorldNotif
To C#, I think you mean:
public class HelloWorldProcessor : INotifProcessor<HelloWorldNotif>
{
public void Yell(HelloWorldNotif notif)
{
throw new NotImplementedException();
}
}

Generic Abstract Method

I ran into trouble when trying to create an abstract class and a method in it that was generic in nature.
class GameRoomManager : MonoBehaviour {
public GameRoom GetSomething(string s){
//do things here
return GameRoomvar;
}
}
Now I have another class that does something similar, but different classes involved
class PlayerManager : MonoBehaviour{
public Player GetSomething(string s){
//player related things here
return Playervar;
}
}
I want to have both classes GameRoomManager and PlayerManager inherit from an abstract class Abs
class GameRoomManager : Abs{
public override GameRoom GetSomething<GameRoom>(string s){
return GameRoomvar;
}
}
where
public abstract class Abs{
public T GetSomething<T>(string s);
}
I've seen a few answers on this topic when I was looking for solutions, and all suggested the abstract class itself be generic. I don't want to make the abstract class generic, since examples I saw would have me do class GameRoomManager : Abs<GameRoomManager>. But I want the method to return type GameRoom, not GameRoomManager.
I'm not totally familiar with generics, so please point me in the right direction if I'm going wrong
You have to have something in common with PQR and HIJ for the classes to use a common method.
Plan A
Connect things with interfaces.
public interface IPart
{
// put things here that are common between Part and GameRoom
int ID { get; }
}
public interface IAbs
{
IPart GetSomething(string name);
}
public class GameRoom : IPart
{
public int ID { get; set; }
}
public class GameRoomManager : IAbs
{
GameRoom part;
#region IAbs Members
public GameRoom GetSomething(string name)
{
return part;
}
IPart IAbs.GetSomething(string name)
{
return GetSomething(name);
}
#endregion
}
public class Player : IPart
{
public int ID { get; set; }
}
public class PlayerManager : IAbs
{
Player part;
#region IAbs Members
public Player GetSomething(string name)
{
return part;
}
IPart IAbs.GetSomething(string name)
{
return GetSomething(name);
}
#endregion
}
Plan B
Use a base class with a generic type & interfaces
public interface IItem
{
// put things here that are common between Part and GameRoom
int ID { get; }
}
public class GameRoom : IItem
{
public int ID { get; set; }
}
public class Player : IItem
{
public int ID { get; set; }
}
public interface IAbs
{
IItem GetItem(string guid);
}
public abstract class Abs<T> : IAbs
where T : IItem
{
protected abstract T GetItem(string name);
protected Abs(T item)
{
this.Item=item;
}
protected T Item { get; private set; }
#region IAbs Members
IItem IAbs.GetItem(string name)
{
return GetItem(name);
}
#endregion
}
public class GameRoomManager : Abs<GameRoom>
{
public GameRoomManager(GameRoom room) : base(room)
{
}
protected override GameRoom GetItem(string guid)
{
return Item;
}
public GameRoom GetRoom(string guid) { return GetItem(guid); }
}
public class PlayerManager : Abs<Player>
{
public PlayerManager(Player player)
: base(player)
{
}
protected override Player GetItem(string guid)
{
return Item;
}
public Player GetPlayer(string guid) { return GetItem(guid); }
}
here is some example usage:
class Program
{
static void Main(string[] args)
{
List<IAbs> managers=new List<IAbs>();
var pm=new PlayerManager(new Player() { ID=1001 });
var gm=new GameRoomManager(new GameRoom() { ID=2050 });
managers.Add(pm);
managers.Add(gm);
IItem part = managers[0].GetItem("0000");
}
}

Categories

Resources