从 List中获取一个元素基于ID

发布于 2024-10-01 01:58:27 字数 1341 浏览 11 评论 0原文

这个问题与这个问题相关: 给定 System.Type T,反序列化列表< /a>

给定此函数来检索所有元素的列表...

 public static List<T> GetAllItems<T>()
 {
    XmlSerializer deSerializer = new XmlSerializer(typeof(List<T>));
    TextReader tr = new StreamReader(GetPathBasedOnType(typeof(T)));
    List<T> items = (List<T>)deSerializer.Deserialize(tr);
    tr.Close();
 }

...我想创建一个函数来仅检索具有所需 UID(唯一 ID)的元素中的一项:

public static System.Object GetItemByID(System.Type T, int UID)
{

    IList mainList = GetAllItems<typeof(T)>();
    System.Object item = null;

    if (T == typeof(Article))
        item = ((List<Article>)mainList).Find(
            delegate(Article vr) { return vr.UID == UID; });
    else if (T == typeof(User))
        item = ((List<User>)mainList).Find(
            delegate(User ur) { return ur.UID == UID; });

    return item;
}

但是,这不起作用,因为 GetAllItems(); 调用格式不正确。

问题 1a:假设所有调用 GetItemByID() 的类都将 UID 作为其中的元素,如何修复第二个函数以正确返回唯一元素?我很乐意能够执行 public static; GetItemByID(int UID)(如果可能)。

问题1b:同样的问题,但假设我无法修改GetItemByID的函数原型?

This question is related to this question: Given System.Type T, Deserialize List<T>

Given this function to retrieve a list of all elements...

 public static List<T> GetAllItems<T>()
 {
    XmlSerializer deSerializer = new XmlSerializer(typeof(List<T>));
    TextReader tr = new StreamReader(GetPathBasedOnType(typeof(T)));
    List<T> items = (List<T>)deSerializer.Deserialize(tr);
    tr.Close();
 }

...I want to create a function to retrieve just one item of those with the needed UID (Unique ID):

public static System.Object GetItemByID(System.Type T, int UID)
{

    IList mainList = GetAllItems<typeof(T)>();
    System.Object item = null;

    if (T == typeof(Article))
        item = ((List<Article>)mainList).Find(
            delegate(Article vr) { return vr.UID == UID; });
    else if (T == typeof(User))
        item = ((List<User>)mainList).Find(
            delegate(User ur) { return ur.UID == UID; });

    return item;
}

However, this does not work since GetAllItems<typeof(T)>(); call is not properly formed.

Question 1a: How can I fix the second function to properly return a unique element, given that all classes that will call GetItemByID() have UID as an element in them? I'd love to be able to do public static <T> GetItemByID<T>(int UID) if possible.

Question 1b: Same question, but suppose I cannot modify the function prototype of GetItemByID?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

生生漫 2024-10-08 01:58:27

1a.确保所有 T 都实现定义属性 UID 的接口 IUniqueIdentity,然后限制泛型方法仅接受 IUniqueIdentity 类型。所以:

public static T GetItemById<T>(int UID) where T:IUniqueIdentity
{
    IList<T> mainList = GetAllItems<T>();

    //assuming there is 1 or 0 occurrences, otherwise FirstOrDefault
    return mainList.SingleOrDefault(item=>item.UID==UID); 

}

public interface IUniqueIdentity
{
    int UID{get;}
}

1a. Ensure that all T implement interface IUniqueIdentity which defines a property UID then constrain a generic method to accept only IUniqueIdentity types. So:

public static T GetItemById<T>(int UID) where T:IUniqueIdentity
{
    IList<T> mainList = GetAllItems<T>();

    //assuming there is 1 or 0 occurrences, otherwise FirstOrDefault
    return mainList.SingleOrDefault(item=>item.UID==UID); 

}

public interface IUniqueIdentity
{
    int UID{get;}
}
你曾走过我的故事 2024-10-08 01:58:27

假设所有调用 GetItemByID() 的类都将 UID 作为其中的元素,如何修复第二个函数以正确返回唯一元素?

将 GetItemByID 方法修改为通用方法:public static T GetItemByID(int UID)

同样的问题,但假设我无法修改 GetItemByID 的函数原型

不起作用,正如您所指出的,因为调用泛型方法需要了解类型 T在编译时。相反,请使用 MethodInfo.MakeGenericMethod()为 T 的特定 Type 创建对方法的封闭形式引用。

public static System.Object GetItemByID(System.Type type, int UID) 
{
    Type ex = typeof(YourClass);
    MethodInfo mi = ex.GetMethod("GetItemByID");

    MethodInfo miConstructed = mi.MakeGenericMethod(type);

    // Invoke the method.
    object[] args = new[] {UID};
    return miConstructed.Invoke(null, args);
}

How can I fix the second function to properly return a unique element, given that all classes that will call GetItemByID() have UID as an element in them?

Modify the GetItemByID method to itself be generic: public static T GetItemByID<T>(int UID)

Same question, but suppose I cannot modify the function prototype of GetItemByID

GetAllItems<typeof(T)>() does not work, as you've noted, since calling generic methods requires knowledge of the type T at compile time. Instead, use MethodInfo.MakeGenericMethod() to create a closed form reference to the method for a particular Type of T.

public static System.Object GetItemByID(System.Type type, int UID) 
{
    Type ex = typeof(YourClass);
    MethodInfo mi = ex.GetMethod("GetItemByID");

    MethodInfo miConstructed = mi.MakeGenericMethod(type);

    // Invoke the method.
    object[] args = new[] {UID};
    return miConstructed.Invoke(null, args);
}
↙厌世 2024-10-08 01:58:27

如果您不介意其成本,那么可以使用 Reflection 来实现以下功能:

public static System.Object GetItemByID(System.Type T, int UID)
{

    IList mainList = GetAllItems().OfType<typeof(T)>();

    return mainList.Find(i => (int)(i.GetType().GetFields().Where(f => f.Name == "UID").FirstOrDefault().GetValue(i)) == UID);

}

它基本上使用 Reflection 来检索名为 UID 的字段的值。

仅当您无法更改 ArticleUser 时才使用此选项,因为这些应该从一个接口继承以允许访问 UID 字段而不必反映它们。

Here's something in Reflection if you don't mind its cost:

public static System.Object GetItemByID(System.Type T, int UID)
{

    IList mainList = GetAllItems().OfType<typeof(T)>();

    return mainList.Find(i => (int)(i.GetType().GetFields().Where(f => f.Name == "UID").FirstOrDefault().GetValue(i)) == UID);

}

It basically uses Reflection to retrieve the value of a field called UID.

Use this only if you don't have the ability to change Article or User, since those should be inheriting from one interface to allow access to a UID field without having to reflect them.

一口甜 2024-10-08 01:58:27

不确定它是否适合您的系统,但您是否考虑过实现 KeyedCollection 而不仅仅是通用列表?

http://msdn.microsoft.com/en-us /library/ms132438%28VS.95%29.aspx

或者可能会从基类代码中深入了解自定义解决方案。

Not sure if it fits into your system as is, but have you thought about implementing a KeyedCollection instead of just a generic list?

http://msdn.microsoft.com/en-us/library/ms132438%28VS.95%29.aspx

Or there might be some insight into a custom solution from the base class code.

花开柳相依 2024-10-08 01:58:27

针对您的 1A,通常的解决方案是将 UID 属性提取到

interface IHasUID { public int UID { get; } }

ArticleUser 和其他任何内容都实现的文件中;然后添加约束

public static T GetItemByID<T>(int UID) where T : IHasUID

如果您无法控制 ArticleUser 等类型,并且无法让它们实现此接口,那么您'基本上是**,并且您将无法以类型安全的方式执行此操作。

In response to your 1A, the usual solution is to extract the UID property into an

interface IHasUID { public int UID { get; } }

which both Article, User, and whatever else implement; and then add a constraint

public static T GetItemByID<T>(int UID) where T : IHasUID

If you don't have control over the types Article, User, et al, and you can't make them implement this interface, then you're basically ** and you won't be able to do this in a typesafe way.

旧情勿念 2024-10-08 01:58:27

我这样做的方法是使用 lambda。也许我过于简化了您实际想要完成的任务,但以下是我在 MVC5 应用程序中通过 Id 从列表中获取对象的方法:

...
List<TodoModel> todos = new List<TodoModel>() {
    new TodoModel() {
        id = 0,
        name = "Laundry!",
        desc = "Whites and darks."
    },
    new TodoModel() {
        id = 1,
        name = "Dishes",
        desc = "Oh, first buy dishes."
    },
    new TodoModel() {
        id = 2,
        name = "Twitter Bootstrap",
        desc = "Check out Grids."
    }
};

ViewBag.Item = todos.Find(o => ((TodoModel)o).id == id);

return View();
...

当然,这是简化的示例,但我认为这可能会派上用场提问者或其他人。

The way I'm doing it is by using a lambda. Maybe I'm over-simplifying what you actually want to accomplish, but here's how I'm getting an object out of a list by its Id in an MVC5 app:

...
List<TodoModel> todos = new List<TodoModel>() {
    new TodoModel() {
        id = 0,
        name = "Laundry!",
        desc = "Whites and darks."
    },
    new TodoModel() {
        id = 1,
        name = "Dishes",
        desc = "Oh, first buy dishes."
    },
    new TodoModel() {
        id = 2,
        name = "Twitter Bootstrap",
        desc = "Check out Grids."
    }
};

ViewBag.Item = todos.Find(o => ((TodoModel)o).id == id);

return View();
...

Simplified example, of course, but thought this may come in handy for the Questioner or others.

椵侞 2024-10-08 01:58:27

System.Type已经是一个类型,不需要做typeof。

那么我会这样做:
if (T == typeof(文章))
item = ((List)mainList).Find(vr => vr.UID == UID);

System.Type is already a type, no need to do typeof.

then I would do:
if (T == typeof(Article))
item = ((List)mainList).Find(vr => vr.UID == UID);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文