好吧,我想我有一些重复的代码,可以使用泛型。
我有两个不同的Xml文件,我打开,查询和返回绑定到GridViews的集合。这些集合是使用xml中的数据填充的自定义类的列表。每个gridview都有相应的自定义类。目前我有两个,并说这些类的名称是 XmlDataSource1 和 XmlDataSource2 。
以下是使用XmlDataSource1作为示例的当前工作示例。请注意,XmlDataSource1对象的构造函数从查询中获取XElements并填充自身。没什么了不起的。
GridView gv = new GridView();
gv.DataSource = GetXmlDataSource1(pathToXmlFile);
gv.DataBind();
public List<XmlDataSource1> GetXmlDataSource1(string pathToXmlFile)
{
XDocument xml = XDocument.Load(pathToXmlFile);
IEnumerable<XmlDataSource1> query = from s in xml.Descendants("NodeForXml1")
select new XmlDataSource1(s);
// Where clauses based on user inputs (deferred execution)
query = query.Where(x => x.ID = SomeUserInputId);
// More of these where clauses if they have inputs for them...
// Convert to a List and return
return query.ToList();
}
现在,要实现GetXmlDataSource2()方法,它就像98%一样。当然,主要区别在于创建XmlDataSource2对象的新实例的linq查询的选择部分,“NodeForXml2”后代目标节点,以及一些适用/不适用的where子句。
如何使这些GetXmlDataSource#方法通用?理想情况下,我想按照下面的说法调用它,这是我尝试过但我无法获取linq查询的选择部分来调用正确数据对象的构造函数。
GridView gv1 = new GridView();
GridView gv2 = new GridView();
gv1.DataSource = GetXmlDataSource<XmlDataSource1>(pathToXmlFile);
gv2.DataSource = GetXmlDataSource<XmlDataSource2>(pathToXmlFile);
gv1.DataBind();
gv2.DataBind();
public List<T> GetXmlDataSource<T>(string pathToXmlFile)
{
// The type of T in case I need it
Type typeOfT = typeof(T);
XDocument xml = XDocument.Load(pathToXmlFile);
// How to make new XmlDataSource1 and 2 objects?? This statement doesn't work.
IEnumerable<T> query = from s in xml.Descendants("NodeForXml1")
select new T(s);
// How to return the IEnumerable query to a List of the T's?
return query.ToList();
}
我有多远?我接近了吗?
答案 0 :(得分:2)
一种解决方案可能是使用Activator.CreateInstance
IEnumerable<T> query = from s in xml.Descendants("NodeForXml1")
select (T)Activator.CreateInstance(typeOfT, s);
但要注意性能问题,here是Jon Skeet处理它的一篇好文章:
显然,这比召集代表要慢 - 大概是因为 试图找到一个带有反射和调用的可访问构造函数 它
因此,如果需要性能,最好将委托传递给GetXmlDataSource1
方法,并使用它在Linq查询中创建所需的实例。
关于您需要访问XmlDataSources公共属性到GetXmlDataSource<T>
方法,您至少有两个解决方案:
1 :创建包含公共属性的界面:
public interface IXmlDataSource
{
string ID { get; set; }
string CommonProperty1 { get; set; }
string CommonProperty2 { get; set; }
}
这个将由您的XmlDataSources实现。这是一个典型的实现:
public class XmlDataSource1 : IXmlDataSource
{
public string ID { get; set; }
public string CommonProperty1 { get; set }
public string CommonProperty2 { get; set }
... // the rest of your code
}
最后,constraining T
类型会授予您在query = query.Where(x => x.ID = SomeUserInputId);
public List<T> GetXmlDataSource<T>(string pathToXmlFile) where T : IXmlDataSource
2 :代理人也可以做到这一点,在这种情况下这是一个典型的电话:
GetXmlDataSource<XmlDataSource1>(pathToXmlFile, (query, result) =>
{
return query.Select(e => new XmlDataSource1(e)).Where(x => x.YourProperty == value);
});
使用GetXmlDataSource<T>
方法签名,如下所示:
public List<T> GetXmlDataSource<T>(string pathToXmlFile, Func<IEnumerable<XElement>, IEnumerable<T>> transform)
{
// The type of T in case I need it
Type typeOfT = typeof(T);
XDocument xml = XDocument.Load(pathToXmlFile);
IEnumerable<XElement> query = from s in xml.Descendants("NodeForXml1")
select s;
// Create and filter XmlDataSource1 instances thanks to the "transform" delegate
return transform(query).ToList();
}
答案 1 :(得分:2)
看起来你很接近 - 一个选项是让调用者在一个函数中传递来创建实例:
public List<T> GetXmlDataSource<T>(string pathToXmlFile,
string elementName,
Func<XElement,T> factoryMethod)
{
...
IEnumerable<T> query = from s in xml.Descendants(elementName)
select factoryMethod(s);
...
}
然后来电者会说:
List<XmlDataSource1> list = GetXmlDataSource1(pathToXmlFile,
"NodeForXml1",
s => new XmlDataSource1(s))