创建一个通用方法

3
我正在尝试编写一个通用方法来处理以下代码:
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);
    }
}

上面的代码仅仅简单地更新存货。我想要制作一个通用的方法,这样我只需要调用那个方法就可以更新不同物品(类)的存货。我对泛型不太熟悉,在研究后我写了以下代码:

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

我遇到了以下错误:

'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?)

如何消除这个错误并以通用方式获取类的属性?

我甚至不知道我写的代码是否好,所以如果您能改进它,那将是很棒的。谢谢。


1
你定义了一个泛型参数约束 where PurchasedEntity : class,这意味着可以使用任何类型作为此泛型参数。因此,泛型方法只能在使用 item 变量时使用 Object 类提供的方法、属性和字段——因为 Object 类是任何类型中最不常见的公共基类... 你需要以一种限制它仅适用于声明了 GlitterId、Quantity、UnitPrice 等属性的(基)类的方式来指定约束。然后编译器将接受代码。 - user2819245
那么,没有办法实现我想要的吗?你能建议一些可能解决我的问题的东西吗? - Syed Farjad Zia Zaidi
1
当然有解决这个问题的方法,但我不知道对于你的需求什么是最好/最优雅的方式... 例如,您可以让您的基类声明一个“通用”ID属性,而您的每个具体实现(Glitter、Powder等)将将此ID属性设置为其GlitterID、PowderID或其他内容。如果必要,您可以保留GlitterID、PowderID等属性,并使您的类实现始终与在基类中声明的ID属性同步。 - user2819245
好的,我要试一下这个...非常感谢。 - Syed Farjad Zia Zaidi
@elgonzo 让我们在聊天室中继续这个讨论 - Syed Farjad Zia Zaidi
显示剩余2条评论
1个回答

1
我假设不是每个PurchasedEntity都有一个GlitterId(根据您的领域,可能也不应该这样)。因此,在PurchasedEntity上定义一个合适的Id属性(或更好地将其提取到接口中):
interface IPurchasedEntity{
    Guid Id {get;}
}

更新 GlitterInventory 实现 IPurchasedEntity

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

那么你的UpdateInventory方法应该读取Id而不是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
    }
}

更新:在尝试从PurchasedEntityInventory中推断您的域之后,将IPurchasedEntity称为IInventory并在其中定义您的公共属性可能更有意义。

非常感谢,@elgonzo也建议了同样的事情,你可以看到我们的聊天记录。我接受这个作为答案,但如果elgonzo在这里写一个答案,那么我会将那个标记为答案,因为他真的花了一些时间与我一起解决这个问题... - Syed Farjad Zia Zaidi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接