3

这个问题与这个问题有关: Given System.Type T, Deserialize List<T>

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

 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<typeof(T)>();呼叫没有正确形成。

问题 1a:鉴于所有将调用 GetItemByID() 的类都将 UID 作为其中的元素,我如何修复第二个函数以正确返回唯一元素?如果可能的话,我很想能够做到 public static <T> GetItemByID<T>(int UID)

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

4

7 回答 7

3

1a。确保所有 T 实现IUniqueIdentity定义属性的接口,UID然后将泛型方法约束为仅接受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;}
}
于 2010-11-08T21:45:30.630 回答
1

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

将 GetItemByID 方法修改为本身是通用的:public static T GetItemByID<T>(int UID)

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

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

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);
}
于 2010-11-08T21:44:10.317 回答
0

我这样做的方式是使用 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();
...

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

于 2014-04-29T07:03:15.607 回答
0

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

interface IHasUID { public int UID { get; } }

,ArticleUser其他任何实现; 然后添加一个约束

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

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

于 2010-11-08T21:42:19.523 回答
0

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

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

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

于 2010-11-08T22:43:12.680 回答
0

如果你不介意它的成本,这里有一些反射:

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

}

它基本上使用反射来检索名为UID.

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

于 2010-11-08T21:56:05.627 回答
-1

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

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

于 2010-11-08T21:45:58.307 回答