Hmmmmm, ok. Now you've lost me. I understand the method returning the type but I can't seem to wrap my head around the syntax needed within the manager class.
Maybe you can point it out for me. I've tried using the "where" contraint for BASETPYE to be derived from "IAsset<TYPE>", "TYPE" must be defined alongside BASETYPE which defeats the purpose of passing a derived class instead of the basetype to begin with.
I've read that generics are based on runtime information many times but I think all those years of C++'s half-assed-everything rotted my brains out. I can't seem to quite comprehend how it works. I can only guess that when a generic type is created it's type is created along with it and treated as an object in its own right.
IAsset.cs
using System;using System.Collections.Generic;using System.Text;[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("CAssetManager")]namespace AssetControl { enum RESELEMENTSTATE { RES_EMPTY = 0, RES_RESERVED, RES_LOADED, }; enum RESLOCKSTATE { RESLSTATE_UNLOCKED, RESLSTATE_LOCKED, }; abstract class IAsset<TYPE> { private RESELEMENTSTATE m_State = RESELEMENTSTATE.RES_EMPTY; private RESLOCKSTATE m_LockState = RESLOCKSTATE.RESLSTATE_UNLOCKED; private string m_FileName; private TYPE m_Data; private CAssetManager<TYPE> m_Manager; static public Type MyType() { return(typeof(TYPE)); } protected internal abstract bool Load(string FileName,out TYPE Data); protected internal abstract bool Release(); public string FileName { get { return(m_FileName); } } public int Lock(out TYPE Data) { m_LockState = RESLOCKSTATE.RESLSTATE_LOCKED; Data = m_Data; return (0); } public int Unlock() { m_LockState = RESLOCKSTATE.RESLSTATE_UNLOCKED; return (0); } public IAsset(string FileName,ref CAssetManager<TYPE> Manager) { //assert Manager reference if(Manager == null) { throw new Exception(AssetFailCode.ManagerRefNotValid); } //set these states first, that way they may //be accessed within the derived class's "Load()" method m_State = RESELEMENTSTATE.RES_LOADED; m_FileName = FileName; //register and assign asset manager classes, making sure //not to create an asset that already exists m_Manager = Manager; try { //this will internally call the "Load()" method, //and throw an exception if it fails m_Manager.Register(this,out m_Data); } catch(Exception e) { //load failed, reset to default states and throw exception m_State = RESELEMENTSTATE.RES_EMPTY; m_FileName = null; throw e; } } ~IAsset() { //assert that the Manager reference was valid when created if(m_Manager == null) { if(!(Release())) { throw new Exception(AssetFailCode.AssetLoadFail); } return; } try { //calls "Release()" internally m_Manager.Unregister(this); } catch(Exception e) { throw e; } } } }
CAssetManager.cs
using System;using System.Collections.Generic;using System.Text;[assembly:System.Runtime.CompilerServices.InternalsVisibleTo("IAsset")]namespace AssetControl { class AssetFailCode { public const string AssetLoadFail = "Asset Failed To Load Properly"; public const string AssetReleaseFail = "Asset Failed To Release Properly"; public const string ManagerRefNotValid = "Manager Reference Passed As NULL"; } public class DataRefCountPair<BASETYPE> { public BASETYPE Data; public int RefCount; public DataRefCountPair() { } public DataRefCountPair(BASETYPE data,int refcount) { Data = data; RefCount = refcount; } } class CAssetManager<BASETYPE> { //maps asset filenames to a reference //of the asset's data and a refcount private SortedDictionary<string,DataRefCountPair<BASETYPE>> m_Database = new SortedDictionary<string,DataRefCountPair<BASETYPE>>(); protected internal void Register(IAsset<BASETYPE> Asset, out BASETYPE Data) { DataRefCountPair<BASETYPE> Entry; //find out if file was previously loaded by checking database. //If it was, asign the asset-class's data to that entry if(!(m_Database.TryGetValue(Asset.FileName,out Entry))) { //if the file was not already loaded, load it now if(Asset.Load(Asset.FileName,out Data)) { //now assign the loaded asset-class's //data to the manager's database Entry = new DataRefCountPair<BASETYPE>(Data,1); m_Database.Add(Asset.FileName, Entry); } else { throw new Exception(AssetFailCode.AssetLoadFail); } } else { //assign asset-class's Data to //the pre-existing element and //increment the refcount Data = m_Database[Asset.FileName].Data; m_Database[Asset.FileName].RefCount++; } } protected internal void Unregister(IAsset<BASETYPE> Asset) { //reduce refcount by one, if refcount reaches zero //set that element to NULL and remove it from the database DataRefCountPair<BASETYPE> Entry; m_Database.TryGetValue(Asset.FileName,out Entry); if(Entry.RefCount == 1) { m_Database.Remove(Asset.FileName); } else { m_Database[Asset.FileName].RefCount--; } if(!(Asset.Release())) { throw new Exception(AssetFailCode.AssetReleaseFail); } } } }
BitmapAsset.cs (in this case I was testing by readin in a byte froma file and storing it in an int)
using System;using System.Collections.Generic;using System.Text;using AssetControl;using System.IO;namespace AssetFactory { class BitmapAsset : IAsset<int> { protected internal override bool Load(string FileName,out int Data) { //FileStream f = new FileStream(FileName,FileMode.Create,FileAccess.Write); FileStream f = new FileStream(FileName,FileMode.Open,FileAccess.Read); byte[] data = new byte[1]; data[0] = 99; //f.Write(data,0,1); f.Read(data,0,1); Data = data[0]; Console.WriteLine("-File Loaded\nFile Name: {0}\nValue Read: {1}\n",FileName,data[0]); return true; } protected internal override bool Release() { Console.WriteLine("-Bitmap Released Successfully"); return true; } public BitmapAsset(string FileName,ref CAssetManager<int> Manager) : base(FileName,ref Manager) { } } }