Syed Farjad Zia Zaidi
Syed Farjad Zia Zaidi

Reputation: 3360

Creating a generic method

I am trying to make a generic method for the following code:

foreach (var glitter in glitterpurchase.GlitterPurchaseDetails)
{
    var glitterInventory = _db.GlitterInventoriesRepository.GetAll(m => m.GlitterId == glitter.GlitterId);
    if (!glitterInventory.Any())
    {
        var newInventory = new GlitterInventory
        {
            GlitterId = glitter.GlitterId,
            Quantity = glitter.Quantity,
            TotalAmount = (decimal)glitter.Quantity * glitter.UnitPrice,
            UnitPrice = glitter.UnitPrice,
            CreatedBy = User.Identity.Name,
            CreatedDate = DateTime.Now,
        };
        _db.GlitterInventoriesRepository.Insert(newInventory);
    }
    else                    
    {
        var updateInventory = glitterInventory.First();
        updateInventory.Quantity += glitter.Quantity;
        updateInventory.TotalAmount += (decimal)glitter.Quantity * glitter.UnitPrice;
        updateInventory.UnitPrice = (decimal)updateInventory.Quantity / updateInventory.TotalAmount;
        updateInventory.UpdatedBy = User.Identity.Name;
        updateInventory.UpdatedDate = DateTime.Now;
        _db.GlitterInventoriesRepository.Update(updateInventory);
    }
}

The code above just simply updates the inventory. I want to make a generic method so that I can just call that method and update the inventory of different items ( classes ). I am not good with generics and after researching I have written the following code:

public virtual void UpdateInventory<PurchasedEntity, Inventory>(IEnumerable<PurchasedEntity> purchaseDetails, GenericRepository<Inventory> inventory, Expression<Func<Inventory, bool>> filterForInventory) 
            where PurchasedEntity : class
            where Inventory : class

{
    foreach (var item in purchaseDetails)
    {
        var glitterInventory = inventory.GetAll(filterForInventory);
        if (!glitterInventory.Any())
        {
            var newInventory = (Inventory)Activator.CreateInstance(typeof(Inventory), new object[] 
            {
                GlitterId = item.GlitterId,
                Quantity = item.Quantity,
                TotalPrice = (decimal)item.Quantity * item.UnitPrice,
                UnitPrice = item.UnitPrice,
                CreatedBy = User.Identity.Name,
                CreatedDate = DateTime.Now,
            });

            inventory.Insert(newInventory);
        }
        else
        {
            var updateInventory = glitterInventory.First();
            updateInventory.Quantity += item.Quantity;
            updateInventory.TotalAmount += (decimal)item.Quantity * item.UnitPrice;
            updateInventory.UnitPrice = (decimal)updateInventory.Quantity / updateInventory.TotalAmount;
            updateInventory.UpdatedBy = User.Identity.Name;
            updateInventory.UpdatedDate = DateTime.Now;
            inventory.Update(updateInventory);
        }
    }
}

The problem is that I am getting the following error:

'PurchasedEntity' does not contain a definition for 'GlitterId' and no extension method 'GlitterId' accepting a first argument of type 'PurchasedEntity' could be found (are you missing a using directive or an assembly reference?)

How can I remove this error and get the properties of the class generically?

I don't even know if the code I wrote is any good, so kindly if you can improve it, that would be great. Thanks.

Upvotes: 3

Views: 115

Answers (1)

Philip Pittle
Philip Pittle

Reputation: 12315

I'm assuming not every PurchasedEntity has a GlitterId (and probably shouldn't depending on your domain). So, define a suitable Id property on PurchasedEntity (or better yet extract it to an interface):

interface IPurchasedEntity{
    Guid Id {get;}
}

Update GlitterInventory to implement IPurchasedEntity:

public class GlitterInventory : IPurchasedEntity{
     Guid IPurchasedEntity.Id { get{ return GlitterId; }}
}

Then your UpdateInventory method should read Id instead of GlitterId:

public virtual void UpdateInventory<PurchasedEntity, Inventory>(
   IEnumerable<PurchasedEntity> purchaseDetails, 
   GenericRepository<Inventory> inventory, 
   Expression<Func<Inventory, bool>> filterForInventory) 
        where PurchasedEntity : IPurchasedEntity, class
        where Inventory : IPurchasedEntity, class, new()
{
    foreach (var item in purchaseDetails)
    {
        var inventory = new Inventory();
        inventory.Id = item.Id;
       // if you have more standard fields, define them in IPurchasedEntity
    }
}

Update: After trying to infer your domain from PurcahsedEntity and Inventory it might make more sense to call IPurchasedEntity IInventory instead and define your common properties there.

Upvotes: 1

Related Questions