【问题标题】:Trying to Utilise a generic <T> collection尝试使用通用 <T> 集合
【发布时间】:2016-02-05 12:46:46
【问题描述】:

我正在使用 C#,我想我终于有机会了解通用类型了。我有几个需要相同静态方法的强类型对象。而不是为每种类型创建一个静态方法,我认为我可以使其通用。我从未做过但也很想要的东西。

这里是我调用它的地方。

   bool isDuplicate = Utilities.GetDuplicates<RoomBookingModel>(roomBookings);

这是我的静态方法,它位于一个名为 Utilities 的静态类中。

 public static bool GetDuplicates<T>(List<T> pBookings)
    {           
        foreach (var item in pBookings)
        {
            var myVal = item.bookingId
        }
        return true;
    }

所以我想在 foreach 循环中获取 var item 中的值,以便进行比较。它肯定通过了 pBookings 因为我可以悬停并且他们有一个 .Count() 和我的强类型对象的集合。我在这里遗漏了一些东西,可能是一个铸造过程。我想知道是否有人可以告诉我我的不足之处。

var myVal = item.bookingId - 我无法从 item 中获取 bookingID,因为我在这里缺乏一些基本的了解。 bookingId 不存在,我只能访问扩展方法,例如 .toString 和 .equals

各种答案我所做的一切都是基于您提供的所有真正有用的帮助。我使用了安德森皮门特尔。我可能仍然不合时宜,但想在这里获得任何人的想法。

所以基本上我有几个预订模型,都需要检查重复。我真的很想以这种方式理解泛型。所以我做的是。创建了一个基类。

public class BookingBaseModel
{
    public int BookingID { get; set; }
    public DateTime BookingStartDateTime { get; set; }
    public DateTime BookingEndDateTime { get; set; }
}

然后让我的预订课程都继承了所有人的共同点。像这样……

public class RoomBookingModel : BookingBaseModel
{
    public string RoomName{ get; set; }
}

public class vehicleBookingModel : BookingBaseModel
{
    public string vehicleName{ get; set; }
}

然后在我的实用程序静态助手中我做了这个..

 public static void GetDuplicates<T>(List<T> items) where T : BookingBaseModel
    {
        foreach (var item in items)
        {
            int myId = item.ID;
            DateTime startDateTime = item.BookingStartDateTime;
            DateTime endDateTime = item.BookingEndDateTime;

            //Do you logic here
        }
    }

然后终于在相应的控制器动作中做了这样的事情。

房间控制器...

        Utilities.GetDuplicates<RoomBookingModel>(roomBookings);

VehicleController....

        Utilities.GetDuplicates<VehicleBookingModel>(vehicleBookings);

这基本上就是我们以这种方式使用泛型的方式吗?

【问题讨论】:

  • 你的问题到底是什么?
  • 如何用这条线构建它? var myVal item.bookingId
  • 如果每个对象都有一个共同的祖先,这可能会起作用。您应该创建一个接口或一个基类,让这个对象继承自它,然后让通用外观按预期工作。
  • itemT 类型,而不是 BookingModel 类型,因此没有 bookingId。泛型的意义在于您的方法适用于任何类型,而不仅仅是一种。
  • 即使你可以说item.bookingId,该方法的结果仍然不是你想要的。如果您想要的是在有重复项时返回 true。

标签: c# asp.net-mvc generics


【解决方案1】:

编译器没有提示T 是什么类型。如果您有一个具有bookingId 属性的基类(或接口),例如BaseModel,您可以像下面这样约束泛型类型:

public class BaseModel
{
    public int Id { get; set; }
}

public static bool GetDuplicates<T>(List<T> items) where T : BaseModel
{           
    foreach (var item in items)
    {
        var myId = item.Id;
        //Do you logic here
    }
    return true;
}

【讨论】:

    【解决方案2】:

    一旦你进入你的GetDuplicates 方法,你就失去了RoomBookingModel 类型的所有知识。这就是泛型方法的重点——它们应该能够对传递给它们的任何类型采取行动,例如它们中的逻辑应该在任何类型中都是通用的。

    所以你的foreach 循环很好——你知道你已经得到了一个列表,你知道列表可以被迭代。但在里面foreachitem 只是一个T。你不知道它是什么实际类型,因为任何类型都可能被传入。所以从item 访问特定属性或方法是没有意义的——例如,如果我调用GetDuplicates 传递怎么办在List&lt;int&gt;?它不会有 bookingId 属性。

    【讨论】:

    • 我认为这个位是为了什么。 'Utilities.GetDuplicates(roomBookings);'我告诉 成为 RoomBookingModel。如果我将 : RoomBookingModel 添加到我的 Generic 方法中,那么我仍然需要该类型的方法。这就是我挣扎的地方。不过感谢您的建议。
    • @P.Joe Yaeh,但你不会每次都这样。
    • @P.Joe 但同样,如果我传入 List&lt;int&gt; 会怎样?按照你的逻辑,我会告诉Tint。但是你告诉TRoomBookingModel,那么编译器怎么知道该听谁的呢?不能。
    • @P.Joe - 除非您通过对其施加约束来指定 T 是什么,否则您无法做您想做的事,这就是泛型的意义所在!
    • @Ric 我很清楚,我试图用一个例子来向 P. Joe 解释为什么他试图做的事情行不通
    【解决方案3】:

    正如别人写的,你对T一无所知。 LINQ 使用的经典解决方案(例如,参见 GroupBy)是让您的方法接收一个执行密钥提取的委托,例如:

    public static bool GetDuplicates<T, TKey>(List<T> pBookings, Func<T, TKey> selector) 
    {
        foreach (var item in pBookings) 
        {
            TKey key = selector(item);
        }
    
        return true;
    }
    

    然后你可以像这样使用它:

    GetDuplicates(pBookings, p => p.bookingId);
    

    【讨论】:

      【解决方案4】:

      如果你喜欢使用泛型方法,你还必须提供一个泛型方法,它能够从指定类型 T 中生成一个键。幸运的是,我们有 LINQ,它已经提供了构建泛型方法所需的部分:

      internal class Extensions
      {
          public static IEnumerable<T> GetDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
          {
              return source.GroupBy(keySelector)
                           .Where(group => group.Skip(1).Any())
                           .SelectMany(group => group);
          }
      
          public static bool ContainsDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
          {
              return GetDuplicates(source, keySelector).Any();
          }
      }
      

      通过这个(和类型推断),您可以使用这些方法,例如通过调用:

      var hasDuplicates = roomBookings.ContainsDuplicates(item => item.bookingId);
      
      if(hasDuplicates)
      {
          Console.WriteLine("Duplicates found:");
      
          foreach (var duplicate in roomBookings.GetDuplicates(item => item.bookingId))
          {
              Console.WriteLine(duplicate);
          }
      }
      

      【讨论】:

        【解决方案5】:

        我想知道泛型是否真的是这里工作的工具。如果您的每个强类型对象共享一个公共接口,您的需求将会得到更好的满足。

        “我有几个需要相同静态方法的强类型对象。”

        在这种情况下,所有类必须共享一个共同的特征,例如属性BookingId

        因此,您需要通过提取此通用接口来将其形式化:

        public interface IBooking
        {
            int BookingId{ get; }
        }
        

        确保你的每一个强类型项都实现了接口:

        public class RoomBooking : IBooking
        {
            //etc...
        }
        

        现在让你的静态方法接受IBooking 实例:

        public static bool GetDuplicates(IEnumerable<IBooking> pBookings)
        {
            //does pBookings contain items with duplicate BookingId values?
            return pBookings.GroupBy(b => b.BookingId).Any(g => g.Count() > 1);
        }
        

        易于阅读,不会因不必要地使用泛型而混淆。

        【讨论】:

          【解决方案6】:

          由于没有关于T 是什么的限制或提示,因此编译器没有足够的信息。考虑

          bool isDuplicate = Utilities.GetDuplicates<int>(roomBookings);
          

          显然int 没有bookingId 成员。

          T 的每个可能的特定类型都必须有一个公共基类或接口,该基类或接口具有 bookingId,即使这样,您也必须在方法签名中添加通用约束才能访问它。

          【讨论】:

            【解决方案7】:

            也许你正在寻找这样的东西:

            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            
            namespace Duplicates
            {
            
                public static class EnumerableExtensions
                {
                    public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter, IEqualityComparer<I> comparer )
                    {
                        var hashSet = new HashSet<I>(comparer);
                        foreach (var item in enumerable)
                        {
                            var identity = identityGetter(item);
                            if (hashSet.Contains(identity)) return true;
                            hashSet.Add(identity);
                        }
                        return false;
                    }
            
                    public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter)
                    {
                        return enumerable.HasDuplicates(identityGetter, EqualityComparer<I>.Default);
                    }
                }
            
                public class Booking
                {
                    public int BookingId { get; set; }
                    public string BookingName { get; set; }
                }
            
                public class Customer
                {
                    public string CustomerId { get; set; }
                    public string Name { get; set; }
                }
            
            
                class Program
                {
                    static void Main(string[] args)
                    {
                        var bookings = new List<Booking>()
                        {
                            new Booking { BookingId = 1, BookingName = "Booking 1" },
                            new Booking { BookingId = 1, BookingName = "Booking 1" }
                        };
            
                        Console.WriteLine("Q: There are duplicate bookings?. A: {0}", bookings.HasDuplicates(x => x.BookingId));
            
                        var customers = new List<Customer>()
                        {
                            new Customer { CustomerId = "ALFKI", Name = "Alfred Kiss" },
                            new Customer { CustomerId = "ANATR", Name = "Ana Trorroja" }
                        };
            
                        Console.WriteLine("Q: There are duplicate customers?. A: {0} ", customers.HasDuplicates(x => x.CustomerId));
            
                    }
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-06-15
              • 1970-01-01
              • 2012-07-04
              • 2016-05-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多