1

Is it possible that each class object has its own static data store?

I mean, just to perform actions like:

class Program
{
    static void Main(string[] args)
    {
        var car1 = new Car();
        car1.Save(); ////saves in its own storage
        var own1 = new Owner();
        own1.Save(); //saves in its own storage as well           
    }
}

In code I tried, I get such error

'System.InvalidCastException`

at this place var repo = (Repository<IEntity>) CurrentRepository;

Whats wrong and how could I make it?

Whole code is here:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            //var car1 = new Car();
            //car1.Save(); ////saves in its own storage
            //var own1 = new Owner();
            //own1.Save(); //saves in its own storage as well    var car1 = new Car();

        }
    }

    public interface IEntity
    {
        long Id { get; }
    }

    public class Owner : Entity
    {

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public Car Car { get; set; }

        public Owner(string firstName, string lastName, Car car) : base(new Owner())
        {
            FirstName = firstName;
            LastName = lastName;
            Car = car;
        }

        public Owner() : base()
        {
        }

    }

    public class Car : Entity
    {
        public string Name { get; set; }
        public int Year { get; set; }

        public Car() : base()
        {

        }

        public Car(string name, int year)
        {
            Name = name;
            Year = year;
        }
    }

    public abstract class Entity : IEntity
    {
        public long Id { get; }

        public static object CurrentRepository { get; set; }

        public Entity(Entity ent)
        {
            Type entityType = ent.GetType();
            var instance = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(entityType));

            CurrentRepository = instance;

        }

        public Entity()
        {
        }

        public void Save()
        {
            var repo = (Repository<IEntity>)CurrentRepository;
            repo.Save(this);
        }

        public void Delete()
        {
            var repo = (Repository<IEntity>)CurrentRepository;
            repo.Delete(this);
        }
    }

    public interface IRepository<T> where T : IEntity
    {
        void Save(T entity);
        void Delete(T entity);
        T Find(long id);
    }

    public class Repository<T> : IRepository<T> where T : class, IEntity
    {
        protected BaseStorage<T> CustomDataStorage;

        public Repository()
        {
            CustomDataStorage = new BaseStorage<T>();
        }

        public void Save(T entity)
        {
            CustomDataStorage.Add(entity);
        }

        public void Delete(T entity)
        {
            CustomDataStorage.Remove(entity);
        }

        public T Find(long id)
        {
            throw new NotImplementedException();
        }
    }
    public class BaseStorage<T> : IStorage<T>
    {
        List<T> data = new List<T>();

        public void Add(T entity)
        {
            data.Add(entity);
        }

        public void Remove(T entity)
        {
            throw new NotImplementedException();
        }
    }

    public interface IStorage<T>
    {
        void Add(T entity);
        void Remove(T entity);
    }

}
user1107378
  • 73
  • 1
  • 10
  • Your code in your post is great, but it isn't enough (e.g. `BaseStorage` is missing). Check out https://stackoverflow.com/help/mcve . Ultimately, you need to give us enough source code that we can just copy and paste it into an app on our side and tweak it. – mjwills Jul 06 '17 at 11:18
  • @mjwills `IEntity` is there, just right at the beginning – user1107378 Jul 06 '17 at 11:21
  • @mjwills I updated the question, and I think thats all I got atm – user1107378 Jul 06 '17 at 11:23
  • @mjwills wellp, there was some misspellings and extra symbols, sorry. I edited that I think – user1107378 Jul 06 '17 at 11:31
  • @mjwills I added whole code in one area, so it would be more comfortable for ppl to copy and run. It compiles, I tried just now – user1107378 Jul 06 '17 at 11:41

2 Answers2

4

In code I tried, I get such error

'System.InvalidCastException`

at this place var repo = (Repository) CurrentRepository;

Whats wrong and how could I make it?

That's because you can't directly cast the CurrentRepository, a type of (Repository<Car> or Repository<Owner>) into a Repository<IEntity>.

See here for more information on this...


To achieve what you wanted here, you could try it this way:

  1. Make the Entity class generic (Entity<T>) and constraint the generic type as IEntity
  2. Make the CurrentRepository a type of Repository<Entity<T>>
  3. Move the static initialization of CurrentRepository from instance constructor to the static constructor.
  4. Make the Owner and Car object subclass of Entity<T> with T refers to its own type making it a self referencing generics

Code:

public class Owner : Entity<Owner>
{
  ...
}

public class Car : Entity<Car>
{
  ...
}

public abstract class Entity<T> : IEntity
  where T: IEntity
{
  public long Id { get; }

  public static Repository<Entity<T>> CurrentRepository { get; set; }

  static Entity()
  {
    CurrentRepository = new Repository<Entity<T>>();
  }

  public Entity()
  {      
  }

  public void Save()
  {      
    CurrentRepository.Save(this);
  }

  public void Delete()
  {      
    CurrentRepository.Delete(this);
  }    
}
IronGeek
  • 4,764
  • 25
  • 27
1

One option to consider would be to change Entity as below.

The ConcurrentDictionary is to ensure that you get one repository per type.

public abstract class Entity : IEntity
{
    public long Id { get; }

    public static ConcurrentDictionary<Type, dynamic> CurrentRepository = new ConcurrentDictionary<Type, dynamic>();

    public Entity(Entity ent)
    {
        GetRepository(ent);
    }

    private static dynamic GetRepository(Entity ent)
    {
        Type entityType = ent.GetType();

        return CurrentRepository.GetOrAdd(entityType, type =>
        {
            var instance = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(entityType));
            return instance;
        });
    }

    public Entity()
    {
    }

    public void Save()
    {
        var repo = GetRepository(this);
        repo.Save((dynamic)this);
    }

    public void Delete()
    {
        var repo = GetRepository(this);
        repo.Delete((dynamic)this);
    }
}
mjwills
  • 23,389
  • 6
  • 40
  • 63