尝试使用通用 集合
本文关键字:集合 | 更新日期: 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
什么类型。 如果你有一个基类(或接口(,它有一个具有 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));
}
}
}