3

这个问题是涉及到这样一个问题:Given System.Type T, Deserialize List<T>获取从列表中<T>元素根据ID

鉴于此功能来获取所有的元素列表...

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的函数原型?

回答

0

在回答您的1A,通常的解决办法是将UID属性提取到一个

interface IHasUID { public int UID { get; } } 

这两个ArticleUser,和其他任何实施;然后添加约束

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

如果你没有在类型ArticleUser,等人控制了,你不能让他们实现了这个接口,那么你基本上* *和你将无法以类型安全的方式做到这一点。

1

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

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

同样的问题,但假设我不能修改GetItemByID

的函数原型

GetAllItems<typeof(T)>()不起作用,因为你已经注意,因为调用泛型方法需要在编译时知道类型T.相反,使用MethodInfo.MakeGenericMethod()为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); 
} 
3

1a的特定Type创建一个封闭的形式参照方法。确保所有的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;} 
} 
+0

有趣 - 看起来更清洁。但是,当我尝试编译此错误时,出现错误'“错误无法将lambda表达式转换为委托类型'System.Func ',因为块中的某些返回类型不会隐式转换为委托返回类型“' – 2010-11-08 22:56:05

+0

我在lambda中使用赋值而不是相等。固定。 – spender 2010-11-09 01:04:33

-1

System.Type已经是一个类型,不需要做typeof。(T == typeof(Article)) item =((列表)mainList).Find(vr => vr.UID == UID);

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字段的值。

使用这个只有当你没有改变ArticleUser,因为这些应该从一个接口继承允许访问一个UID场,而不必以反映他们的能力。

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

简化的例子,当然,但思想这对于发问者或其他人可能会派上用场。