Automating an object repository for a game - c#

Hello guys i am having trouble designing an object repository for a game:
class ObjectRepository
{
private readonly LevelType _levelType;
private readonly BaseObject[] _darkForestObjects = new BaseObject[]
{ new DarkForestTreeA(), new DarkForestTreeB(), new DarkForestTreeC() };
private readonly BaseObject[] _lightForestObjects = new BaseObject[]
{ new LightForestTreeA(), new LightForestTreeB(), new LightForestTreeC() };
public ObjectRepository(LevelType lt)
{
_levelType = lt;
}
public BaseObject GetObject(int obj)
{
if (obj < 0 || obj > _darkForestObjects.Length)
{
Debug.LogError("Object does not exist.");
return null;
}
switch (_levelType)
{
case LevelType.DarkForest:
return _darkForestObjects[obj];
case LevelType.LightForest:
return _lightForestObjects[obj];
}
return null;
}
}
public enum LevelType
{
DarkForest = 0,
LightForest = 1,
}
I am searching for a way of automating this class.By automating it i mean that i don't want every time i create a new object deriving from BaseObject to come inside the Repository class and modify arrays.It just doesn't seem natural.Can anybody point me out a suggestion for automation?

I'll take a gander at this, so please let me know if I'm assuming things wrong.
You'll need:
A repository that'll hold your BaseObject-derived instances;
Said repository must be accessible by the BaseObject class;
Whenever a BaseObject is created, it adds itself to the repository.
Now, I've noticed that you hold instances for both dark and light versions of your objects. So I'd additionally suggest a holder class for both light and dark versions of a given 'object'. Like this:
class CompoundObject
{
public BaseObject LightVersion;
public BaseObject DarkVersion;
}
Your repository then hold CompoundObject-derived objects, and instead of BaseObject objects adding themselves at creation time, CompoundObject objects would do it.
Now about Array manipulations, you may be right; it can be somewhat clunky. I'd suggest the adoption of List<CompoundObject> instead of CompoundObject[]. A generic List offer very handy methods like Add and Remove that can streamline your collection manipulation.

If I were you, I would opt for a more generic solution using interfaces.
Considering your example, I assume that you have multiple level types which have their own specific TreeA, TreeB and TreeC implementations.
If I understood right, I would rather use interface for each tree type. Example for TreeA :
public interface ITreeA
{
// any common public members here
}
public class DarkForestTreeA : ITreeA, BaseObject
{
...
}
public class LightForestTreeA : ITreeA, BaseObject
{
...
}
This way, you can ask your repository to provide the ITreeA implementation specific to the level type. Something like :
public T GetObject<T>() // where T could be ITreeA, ITreeB...
{
...
}
So you could call myRepo.GetObject() and get a DarkForestTreeA object if level type is DarkForest for example.
To have this behavior "automated", you could declare all the specific implementations of DarkForest in a unique namespace and then use reflexion to find the class of the namespace that implements ITreeA for example. This may not be very efficient in terms of performance but it gives you great flexibility as you will just have to add new classes in your namespace to have them available from the repository. However, it can also bring other problems (for example, what would happen if you have two classes implementing ITreeA in the same namespace ?).
See Getting all types in a namespace via reflection and Getting all types that implement an interface with C# 3.0 for implementation details.
I have to admit it isn't the simplest solution.
You could consider simpler thing like defining a dictionary for object type (treeA, treeB) and then define a dictionary for each level type mapping the object type to its concrete implementation.
For example :
public enum ObjectType
{
TreeA,
TreeB,
TreeC,
}
Dictionary<ObjectType, Type> DarkForestObjectTypes = new Dictionary<ObjectType, Type>()
{
{ ObjectType.TreeA, typeof(DarkForestTreeA) },
{ ObjectType.TreeB, typeof(DarkForestTreeB) }
...
}
I won't go into more details as this answer looks a bit messy but hopefully it will give you ideas to go on with.

Related

Best approach to instantiate object based on string

I'd like to discuss about the best approach (in C#) to instantiate an object based on an input string. Let me explain.
Let'say I have a base class:
public abstract class BaseCar
{
public asbtract int GetEngineID();
//Other stuff...
}
Then I have several implementations of this class, let's say:
public class SportCar : BaseCar
{
public override int GetEngine()
{
//Specific implementation
}
}
public class OtherCar: BaseCar
{
public override int GetEngine()
{
//Specific implementation
}
}
And so on...
What I'd like to do is to make a static CarFactory class which has a CreateCar method which accepts a string as a parameter and returns a BaseCar instance, depending on what string you give. The string would be a name of a child class.
For example, if I call CarFactory.CreateCar('SportCar') it should return a SportCar instance.
I know I could use a simple switch statement to check which car has been requested and create a new instance based on that but I don't like this approach for two reasons:
I plan to have a lot of child classes, hard-coding every case wouldn't be too easy to mantain
I plan to implement an inizialization procedure to also give some initial values to the objects I create (using Reflection), so mixing hard-coding and reflection doesn't seem to be a good idea for me.
What I was thinking about is to use the Assembly.CreateInstance from System.Reflection to create an instance of the specified class but since this is the first time I approach this problem, I don't know if there are better ways to do that. Is this a valid approach ?
Considering the input string will come from an XML file, is there a simplier method ? Maybe my issue is already handled in some .NET Assembly which I'm missing.
Here is what I came up with. A generic factory class that automatically registers all types that are a subclass of the given type, and allows you to instantiate them via their name. This is somewhat related to the approach shown in the Java SO question linked by #Achilles in the comments, only that there is no initialisation function associated with the type.
There is no need to maintain an enum/switch combination of all types. It should also be somewhat easily extendable to handle your proposed reflection based initialisation.
static class StringFactory<T> where T : class
{
static private Dictionary<string, Type> s_dKnownTypes = new Dictionary<string, Type>();
static StringFactory()
{
RegisterAll();
}
static private void RegisterAll()
{
var baseType = typeof(T);
foreach (var domainAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in domainAssembly.GetTypes()
.Where(t => t.IsSubclassOf(baseType)))
{
s_dKnownTypes.Add(type.Name, type);
}
}
}
static public T Create(string _sTypeName)
{
Type knownType;
if (s_dKnownTypes.TryGetValue(_sTypeName, out knownType))
{
return (T)Activator.CreateInstance(knownType);
}
throw new KeyNotFoundException();
}
}
Assuming the classes of your question exist, you would instantiate a specific car like this:
var car = StringFactory<BaseCar>.Create("SportsCar");
DoSomethingWith(car.EngineID());
Since your question was for a discussion about the best approaches, please consider this only one of them. I have not used this in a production environment, and it is entirely possible that it is the wrong approach to your specific situation. It works well enough to show the general principle, however, and should provide a starting point for further discussion.

How to convert class with generic type to class with object as generic type in C#

Hello I'm using Visual Studio 2005 (because I need compact framework support) and my problem is with generics.
I have created an abstract class called AbstractDAO which is my base
From that I am creating other classes like DocumentDAO,HeaderDAO etc which represent different tables on my database
What I wish to do is retrieve a certain number of the above mentioned DAO classes, but as an AbstractDAO (the abstract class has a number of concrete implementations that I wish to use)
What I tried is
AbstractDAO<object> dao = new DocumentDAO();
AbstractDAO<object> dao = (AbstractDAO<object>)new DocumentDAO();
AbstractDAO<T> dao = new DocumentDAO();
I need the above because I have created a function that transfers data from one table to another similar table in a different database, so it would (if it worked) go something like this
AbstractDAO<object> dao_local = new DocumentDAO(local_database);
AbstractDAO<object> dao_remote = new DocumentDAO(remote_database);
do_transfer(dao_local,dao_remote)
void do_transfer(AbstractDAO<object> from, AbstractDAO<object> to) {
List<object> items = from.get_all();
to.insert(items);
}
Is there any way to do the above?
That will only work if your class hierachy is like this:
class DocumentDAO : AbstractDAO<object> {
//...
}
By your comment it seems like you have a type hierarchy like this:
class DocumentDAO : AbstractDAO<SomeType> {
public override SomeType Foo() {
//...
return someValue;
}
//...
}
class AbstractDAO<T> {
public abstract T Foo();
//...
}
You probably want to refactor AbstractDAO to implement a non generic interface like IAbstractDAO:
class IAbstractDAO {
object Foo();
//...
}
class AbstractDAO<T> {
public object Foo() {
return Foo();
}
public abstract T Foo();
//...
}
Any implementation of AbstractDAO<T> is compiled to a separate object type where T is replaced with the type. See "Is generics runtime or compile time polymorphism?" for more information on how this happens. In short, don't let the <T> fool you.
This means that you can't assign DocumentDAO to AbstractDAO<object> any more than you can assign String to it. Also a generic type is not the same as inheriting, which seems to be what you are trying to achieve.
In either case there are two standard solutions, as already mentioned.
The first is to operate on interfaces. You create an interface for the common properties and have AbstractDAO<T> or any other inherit from this. Then most of the time you simply operate on interfaces. Exactly how you organize it is up to you.
The second is to perform a shallow copy of the object. This means copying values and references from one object to the other. For this you usually use an object mapper like AutoMapper. This tutorial should get you started..
You can try to use Automapper to transfer your objects like this:
void do_transfer(AbstractDAO<FirstType> from, AbstractDAO<SecondType> to)
{
Mapper.Initialize(cfg=>cfg.CreateMap<FirstType, SecondType>);
List<FirstType> fromItems = from.get_all();
List<SecondType> itemsToInsert =
Mapper.Map<List<FirstType>, List<SecondType>>(fromItems);
to.insert(itemsToInsert);
}
By default automapper will map fields with same names. You can create configurations for complex type mapping.
So I finally found the answer to what I was trying to do, instead of assigning abstractDAO to something I created a factory that would retrieve the required AbstractDAO according to what type the generic was, and used this function
private bool transfer<T>(){
AbstractDAO<T> local = DAOFactory.get<T>(local_database);
AbstractDAO<T> remote = DAOFactory.get<T>(remote_database);
List<T> items = local.get_all();
foreach (T item in items) {
remote.insert(item);
}
}
That way I can call this function like this:
transfer< Document >();
transfer< Header >();
etc. and do a full transfer
edit: just for completeness' shake this is the factory I created
public static AbstractDAO<T> get<T>(Database database) {
Type t = typeof(T);
if (t == typeof(Document)) {
return new DocumentDAO(database) as AbstractDAO<T>;
} else if (t == typeof(Header)) {
return new HeaderDAO(database) as AbstractDAO<T>;
} etc.
}

Interacting with a list of generically typed complex objects

I've been searching for awhile to see if anyone was trying to do something close to this and I find a bunch of people trying to interact with a generically typed List. I instead need to interact with a List of complex objects who are generically typed. Here's the current code.
public class RequestBundleItem<T> where T : BaseJsonResponseMessage
{
public T Response { get; private set; }
//intializers - code not needed
public void SetResponse(String jsonResponse)
{
Response = (T)jsonResponse.JsonToObject<T>();
}
}
public class RequestBundleManager
{
private List<RequestBundleItem<T>> BundleItems;
public async Task<List<RequestBundleItem<T>>> ProcessItemsAsync()
{
List<Task<JsonValueEventArgs>> tasks = //create tasks from bundleitems;
for (var i = 0; i < tasks.Count(); i++)
{
Task<JsonValueEventArgs> curTask = tasks[i];
var args = await curTask;
BundleItems[i].SetResponse(args.ValueAsText);
}
return BundleItems;
}
public void AddItem<T>(RequestBundleItem<T> newItem) where T : BaseJsonResponseMessage
{
BundleItems.Add(newItem);
}
}
This line is what's causing the problem
private List<RequestBundleItem<T>> BundleItems;
I don't know how to define this list since T is generic and just needs to implement BaseJsonResponseMessage but I don't want to type the RequestBundleManager itself.
SOLUTION:
I ended up removing the generic from the RequestBundleItem and the consumer is responsible for knowing the response type it needs back.
Make RequestBundleManager generic also:
public class RequestBundleManager<T>
And now you list can be defined with type T. Of course, you have to make sure that the T you use when creating your RequestBundleManger is the same as the one you used for RequestBundleItem, and you list will be homogeneous.
If you want your RequestBundleManager to handle lists with mixed T, then you will need to have RequestBundleItem derive from a base class or else have it implement an interface.
Define the list in your RequestBundleManager like this:
private List<RequestBundleItem<BaseJsonResponseMessage>>
If you don't put a type on the RequestBundleManager, you don't know the specific type of the object inside the list except that it's a BaseJsonResponseMessage. Then it makes sense to just define it like that. It will give you access only to methods defined in BaseJsonResponseMessage though.
If that's not enough, consider defining an interface with all the methods you want to have access to in the RequestBundleManager and put it as a constraint on your type in RequestBundleItem. Something like this:
public class RequestBundleItem<T> where T : BaseJsonResponseMessage, IMyInterface
Then define the list in RequestBundleManager like:
private List<RequestBundleItem<IMyInterface>>

C#, generic way to access different lists within a class

I have a class of 3 different linked lists (for saving the entities in a game I'm working on). The lists are all of objects with the same base type, but I keep them separate for processing reasons. Note that IEntity, IObject and IUndead all inherited from IEntity.
public class EntityBucket
{
public LinkedList<IEntity> undeadEntities;
public LinkedList<IEntity> objects;
public LinkedList<IEntity> livingEntities;
public EntityBucket()
{
undeadEntities = new LinkedList<IEntity>();
objects = new LinkedList<IEntity>();
livingEntities = new LinkedList<IEntity>();
}
public LinkedList<IEntity> GetList(IObject e)
{
return objects;
}
public LinkedList<IEntity> GetList(IUndead e)
{
return undeadEntities;
}
public LinkedList<IEntity> GetList(ILiving e)
{
return livingEntities;
}
}
I have 3 methods for retrieving each of the lists, currently based on their parameters. The fact that there are 3 is fine, since I know each list will in some way or another require its own accessor. Passing an instantiated object is not ideal though, as I may want to retrieve a list somewhere without having an object of similar type at hand. Note that the object here is not even used in the GetList methods, they are only there to determine which version to use. Here is an example where I have an instantiated object at hand:
public void Delete(IUndead e, World world)
{
.....
LinkedList<IEntity> list = buckets[k].GetList(e);
.....
}
I don't like this current implementation as I may not always have an instantiated object at hand (when rendering the entities for example). I was thinking of doing it generically but I'm not sure if this is possible with what I want to do. With this I also need 3 Delete methods (and 3 of any other, such as add and so forth) - one for each type, IUndead, IObject and ILiving. I just feel that this is not the right way of doing it.
I'll post what I have tried to do so far on request, but my generics is rather bad and I feel that it would be a waste for anyone to read this as well.
Finally, performance is very important. I'm not prematurely optimizing, I am post-optimizing as I have working code already, but need it to go faster. The getlist methods will be called very often and I want to avoid any explicit type checking.
So you want a better interface, because, as you said, passing an unnecessary object to GetList just to figure out its type makes little sense.
You could do something like:
public List<IEntity> GetList<T>() : where T:IEntity
{
if(typeof(T)==typeof(IUndead)) return undedEntities;
// and so on
}
And you'll have to call it like this: GetList<IUndead>();
I think an enum is a better idea here:
enum EntityTypes { Undead, Alive, Object };
public List<IEntity> GetList(EntityTypes entityType) { ... }
It's cleaner and makes more sense to me.
EDIT: Using generics is actually not that simple. Someone could call GetList a Zombie type, which implements IUndead, and then you'll have to check for interface implementations. Someone could even pass you a LiveZombie which implements both IUndead and IAlive. Definitely go with an enum.
How about a better implementation to go with that better interface?
public class EntityBucket
{
public LinkedList<IEntity> Entities;
public IEnumerable<T> GetEntities<T>() where T : IEntity
{
return Entities.OfType<T>();
}
}
List<IUndead> myBrainFinders = bucket.GetEntities<IUndead>().ToList();
With this implementation, the caller better add each item to the right list(s). That was a requirement for your original implementation, so I figure it's no problem.
public class EntityBucket
{
Dictionary<Type, List<IEntity>> entities = new Dictionary<Type, List<IEntity>>();
public void Add<T>(T item) where T : IEntity
{
Type tType = typeof(T);
if (!entities.ContainsKey(tType))
{
entities.Add(tType, new List<IEntity>());
}
entities[tType].Add(item);
}
public List<T> GetList<T>() where T : IEntity
{
Type tType = typeof(T);
if (!entities.ContainsKey(tType))
{
return new List<T>();
}
return entities[tType].Cast<T>().ToList();
}
public List<IEntity> GetAll()
{
return entities.SelectMany(kvp => kvp.Value)
.Distinct() //to remove items added multiple times, or to multiple lists
.ToList();
}
}
How about something like the following?
public LinkedList<IEntity> GetList(Type type) {
if (typeof(IUndead).IsAssignableFrom(type)) return undeadEntities;
if (typeof(ILiving).IsAssignableFrom(type)) return livingEntities;
if (typeof(IObject).IsAssignableFrom(type)) return objects;
}
Then you would call it like this:
var myUndeads = GetList(typeof(IUndead));
var myLivings = GetList(typeof(ILiving));
// etc
The same type of logic could be implemented in your deletes, add, and other methods, and you never need a concrete instance of an object to access them.
The IsAssignableFrom logic handles subclassing just fine (i.e. you could have a CatZombie, which derives from Zombie, which implements IUndead, and this would still work). This means you still only have to create one Delete method, something like the following:
public void Delete(IEntity e, World world) {
if (typeof(IUndead).IsAssignableFrom(type)) undeadEntities.Remove(e);
if (typeof(ILiving).IsAssignableFrom(type)) livingEntities.Remove(e);
if (typeof(IObject).IsAssignableFrom(type)) objects.Remove(e);
}
EDIT: I noticed your comment on zmbq's answer regarding performance; this is definitely NOT fast. If you need high performance, use an enum-style approach. Your code will be more verbose and require more maintenance, but you'll get much better performance.
Seems to me you could just implement a Dictionary
of named LinkedList's and refer to them
by name or enum.
That way adding or removing lists is just an
implementation issue and no separate class to deal with.

Help me understand how to use a class in OOP C#

I'm creating an application that basically downloads and uploads files from various types of locations. I asked some advice on here and I was told that I should take an Object Oriented Approach with something like this, but this is my first real usage of OOP so I'm having a hard time understanding how to carry out what I want. Here is what I have so far:
public class FileListClass
{
public string sourcetype;
public string source;
public string destination;
public string destinationtype;
public bool deleteSource;
}
How do I actually enter a file into here in my main method? When I create a new list based on this class, .Add on the list requires an item of 'FileListClass' type - how do I create this?
you can do some thing lik ethis
FileListClass oFileListClass = new FileListClass();
oFileListClass.sourcetype="";
oFileListClass.source="";
oFileListClass.destination="";
oFileListClass.destinationtype="";
oFileListClass.deleteSource=false;
this will create one object, and you can create as many as possible like this with diffrent values.
if you wana keep this in List then create list of type FileListClass like
List<FileListClass > oListFileListClass = new List<FileListClass >();
then add all of your objects in this like
oListFileListClass.Add(oFileListClass);
Short answer:
var yourList = new System.Collections.Generic.List<FileListClass>();
yourList.Add(new FileListClass
{
sourcetype = "...",
source = "...",
...
});
Longer answer:
The above should work, but do take note that your class is not particularly well-designed (IMHO). It's more of a simple data record/container than a class that's "true" to OO principles. This may be just fine, depending on your requirements.
It's uncommon to expose fields directly in C#. Usually, only properties are exposed: public string SourceType { get; set; }
sourcetype and destinationtype are slightly suspect -- this might be a case where subclassing (class inheritance) might be suitable later on. Even without that, and without me knowing what exactly you're going to store in those two fields, have you considered using enums for them instead of plain strings?
In C#, it's common practice to name public members with CamelCase capitalization.
First, it's a bettere approach to define Enums for your constant types, something like
public enum SourceTypes
{
Network = 0,
WAN =1,
}
ecc. ecc.
then modify your FileLystClass as follows
public class FileListClass
{
public SouceTypes sourceType;
...
public DestinationTypes destinationType;
...
}
then, to answer your question.
You have defined a a class(a type) called FileListClass.
To use it, just create as many instance you want, populating the fields of the objects accordingly to your sources
public void CreateFileListList()
{
for (int i = 0; i <100; i++)
{
FileListClass flo = new FileListClass
flo.sourceType = SourceTypes.WAN;
flo.deletesource = true;
[...]
myList.add(flo);
}
}
I would suggest laying out the basic actions that are needed in your program:
DownloadFrom(String loc);
UploadFrom(String loc);
Then you can build lower levels of your app:
DownloadFrom(String loc);
HTTPConnect();
FTPConnect();
etc..
UploadFrom(String loc);
HTTPConnect();
FTPConnect();
etc..
At this point you can already have a feeling of the structure of your program, you can in fact create classes around your different actions:
class Connect {
HTTPConnect();
FTPConnect();
}
class Download : Connect{
DownloadFrom(String loc);
}
class Upload : Connect{
UploadFrom(String loc);
}
As you can see this is a first approach to OOP. There are many advantages to use a structure of Objects around your program but It would be too hard of an explanation. Try reading Google about it: Advantages of OOP.

Categories

Resources