Generic Abstract Method - c#

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");
}
}

Related

Implement an interface method with a concrete class

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>;
}
}

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.

what kind of factory pattern to implement when methods accept different signatures?

How do I define a factory whose implementations may accept different numbers of parameters?
public abstract class CarFactory
{
public abstract void countStuff(??); //not sure how to define this
}
I would like the factory to be able to create different objects like:
public class BMW : CarFactory
{
public override void countStuff(param1, param2) {}
}
public class Ford : CarFactory
{
public override void countStuff(param1) {}
}
Not sure if "countStuff" should be a factory responsibility, but you could get something similar this way:
public interface ICountParam {}
public class BmwParam : ICountParam
{
public BmwParam(string a)
{
A = a;
}
public string A { get; set; }
}
public class FordParam : ICountParam
{
public FordParam(string a, string b)
{
A = a;
B = b;
}
public string A { get; set; }
public string B { get; set; }
}
public interface ICarFactory<in T> where T : ICountParam
{
void CountStuff(T param);
}
public class BMW : ICarFactory<BmwParam>
{
public void CountStuff(BmwParam param) { }
}
public class Ford : ICarFactory<FordParam>
{
public void CountStuff(FordParam param) { }
}
Usage:
bmw.CountStuff(new BmwParam("A"));
ford.CountStuff(new FordParam("A", "B"));

Factory pattern with 4 layer architecture

In my project i have 4 layers presentation,BL,DL, and dataObjects. i want to implement abstract factory pattern to get the object i want(doctor/Engineer). Is the code below implementing factory pattern?
public interface IProfessional //The Abstract Factory interface.
{
IProfession CreateObj();
}
// The Concrete Factory class1.
public class DocFactory : IProfessional
{
public IProfession CreateObj()
{
return new Doctor();
}
}
// The Concrete Factory class2.
public class EngFactory : IProfessional
{
public IProfession CreateObj()
{
// IMPLEMENT YOUR LOGIC
return new Engineer();
}
}
// The Abstract Item class
public interface IProfession
{
}
// The Item class.
public class Doctor : IProfession
{
public int MedicalSpecialty
{
get; set;
}
public int AreaofExpertise
{
get; set;
}
}
// The Item class.
public class Engineer : IProfession
{
public string Title{
get;set;
}
public int AreaofExpertise
{
get; set;
}
}
// The Client class.
public class AssignProfession
{
private IProfession _data;
public AssignProfession(DataType dataType)
{
IProfessional factory;
switch (dataType)
{
case DataType.Doc:
factory = new EngFactory();
_data = factory.CreateObj();//from here i will get engineer
break;
case DataType.Eng:
factory = new DocFactory();
_data = factory.CreateObj();//from here i will get doctor
break;
}
}
public IProfession GiveProfessional()
{
return _data;
}
}
//The DataType enumeration.
public enum DataType
{
Doc,
Eng
}
Your code does implement the pattern but not to the full extent which C# allows, in other words - you are not using the important benefits of the C# language.
Here is an example of how you can do it better:
class Program
{
static void Main(string[] args)
{
var myEngineer = ProfessionFactory.CreateProffession<Engineer>();
var myDoctor = ProfessionFactory.CreateProffession<Doctor>();
myEngineer.EnginerringStuff();
myDoctor.HealingPeople();
var myEngineer2 = (Engineer)ProfessionFactory.CreateProffession("Engineer");
//using the other method I still have to cast in order to access Engineer methods.
//therefore knowing what type to create is essential unless we don't care about engineer specific methods,
//in that case we can do:
var myEngineer3 = ProfessionFactory.CreateProffession("Engineer");
//which is useless unless we start involving reflections which will have its own price..
}
public interface IProfessionFactory
{
IProfession CreateObj();
}
public interface IProfession : IProfessionFactory
{
string ProfessionName { get; }
}
public abstract class ProfessionFactory : IProfessionFactory
{
public abstract IProfession CreateObj();
public static T CreateProffession<T>() where T:IProfessionFactory, new()
{
return (T)new T().CreateObj();
}
public static IProfession CreateProffession(object dataObj)
{
if (dataObj == "Engineer")
return CreateProffession<Engineer>();
if (dataObj == "Doctor")
return CreateProffession<Doctor>();
throw new Exception("Not Implemented!");
}
}
public class Engineer : IProfession
{
public string ProfessionName
{
get { return "Engineer"; }
}
public IProfession CreateObj()
{
return new Engineer();
}
public void EnginerringStuff()
{}
}
public class Doctor : IProfession
{
public string ProfessionName
{
get { return "Doctor"; }
}
public IProfession CreateObj()
{
return new Doctor();
}
public void HealingPeople()
{}
}
}
It does seem to have all elements of the pattern, however your IProfession is empty. I am going to assume that is just a placeholder and you are going to fill it in with some methods that represent a behavior that is common to all professions.
Contrast that with the example given in Allen Holub's book
He mentions Collection as the AbstractFactory, Iterator as the abstract product, Tree as the concrete factory and the iterators that are returned as concrete products.

How to generalize a class inheriting from another class

I have a class that looks like:
public class InvokeProxy : MarshalRefByObject, IFace
{
public InvokeProxy(IFace face)
{
this.Face = face;
}
private IFace Face { get; set; }
public string Execute(string data)
{
return this.Face.Execute(data)
}
}
And I'm tasked with making it generic. Since I can't inherit from the generic class, I'm somewhat stuck, does anyone know a workaround?
I'm not really sure what you're looking to do by making InvokeProxy into InvokeProxy<T>...does this help?
public class InvokeProxy<T> : MarshalRefByObject, IFace where T : IFace
{
public InvokeProxy(T face)
{
this.Face = face;
}
private T Face { get; set; }
public string Execute(string data)
{
return this.Face.Execute(data);
}
}
Not really sure if I understood the question....
public class InvokeProxy<T> : MarshalRefByObject where T : class
{
public InvokeProxy(T face)
{
this.Face = face;
}
private T Face { get; set; }
public string Execute(string data)
{
return this.Face.Execute(data)
}
}

Categories

Resources