此问题与此问题有关: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的函数原型?
答案 0 :(得分:3)
1a上。确保定义属性IUniqueIdentity
的所有T实现接口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;}
}
答案 1 :(得分:1)
如果所有调用GetItemByID()的类都将UID作为其中的元素,我如何修复第二个函数以正确返回一个唯一元素?
将GetItemByID方法修改为通用:public static T GetItemByID<T>(int UID)
正如您所指出的,同样的问题,但假设我无法修改GetItemByID的函数原型
GetAllItems<typeof(T)>()
不起作用,因为调用泛型方法需要在编译时知道类型T.相反,使用MethodInfo.MakeGenericMethod()
为特定Type
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);
}
答案 2 :(得分:0)
作为对1A的回应,通常的解决方案是将UID属性提取到
中interface IHasUID { public int UID { get; } }
Article
,User
以及其他任何实现的内容;然后添加约束
public static T GetItemByID<T>(int UID) where T : IHasUID
如果您无法控制Article
,User
等类型,并且无法让它们实现此界面,那么您基本上是 * *并且您将无法以类型安全的方式执行此操作。
答案 3 :(得分: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);
}
它基本上使用Reflection来检索名为UID
的字段的值。
仅在您无法更改Article
或User
时使用此选项,因为这些应该从一个界面继承,以允许访问UID
字段而无需反映他们。
答案 4 :(得分:0)
不确定它是否适合您的系统,但是您是否考虑过实施KeyedCollection而不仅仅是通用列表?
http://msdn.microsoft.com/en-us/library/ms132438%28VS.95%29.aspx
或者可以从基类代码中了解自定义解决方案。
答案 5 :(得分: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();
...
当然,简化示例,但认为这对于提问者或其他人来说可能会派上用场。
答案 6 :(得分:-1)
System.Type已经是一个类型,不需要做typeof。
然后我会这样做: if(T == typeof(Article)) item =((List)mainList).Find(vr =&gt; vr.UID == UID);