尝试使用通用 集合

本文关键字:集合 | 更新日期: 2023-09-27 18:33:31

我正在使用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 项中的值,以便我可以进行比较。它绝对通过了 pBookings,因为我可以悬停并且他们有一个.Count(( 与我的强类型对象的集合。我在这里缺少一些东西,可能是铸造过程。我想知道是否有人可以告诉我我在哪里不足。

var myVal = item.bookingId - 我无法从项目中获取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);

车辆控制器....

        Utilities.GetDuplicates<VehicleBookingModel>(vehicleBookings);

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

尝试使用通用 <T> 集合

编译器

没有提示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;
}

一旦你进入了你的GetDuplicates方法,你就失去了RoomBookingModel类型的所有知识。这就是泛型方法的意义所在 - 它们应该能够作用于传递给它们的任何类型,例如,它们中的逻辑应该在任何类型中都是泛型的。

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

正如其他人所写的那样,你对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);

如果要使用泛型方法,还必须提供一个泛型方法,该方法能够从指定的类型 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);
    }
}

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

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

在这种情况下,所有类必须共享一个共同的功能,例如,属性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);
}

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

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

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

显然,int没有bookingId成员。

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

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

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