2

好吧,我想我有一些重复的代码可以用来使用泛型。

我有两个不同的 Xml 文件,我将它们作为绑定到 GridView 的集合打开、查询和返回。这些集合是使用 xml 中的数据填充的自定义类的列表。每个 gridview 都有其对应的自定义类。目前我有两个,并说这些类的名称是XmlDataSource1XmlDataSource2

这是一个使用 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% 一样。当然,主要区别在于 linq 查询的选择部分创建了 XmlDataSource2 对象的新实例、“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();
}

我离我有多远?我接近了吗?

4

2 回答 2

2

一种解决方案可能是使用Activator.CreateInstance

   IEnumerable<T> query = from s in xml.Descendants("NodeForXml1")
                                       select (T)Activator.CreateInstance(typeOfT, s);

但要注意性能问题,是 Jon Skeet 的一篇很棒的帖子:

显然,这比调用委托要慢 - 大概是因为试图找到一个具有反射的可访问构造函数并调用它

因此,如果需要性能,最好将委托传递给您的GetXmlDataSource1方法并使用它在 Linq 查询中创建您需要的实例。

关于您需要将 XmlDataSources 公共属性访问到GetXmlDataSource<T>方法中,您至少有 2 个解决方案:

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
}

最后,约束 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();
}
于 2013-10-24T19:47:07.287 回答
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))
于 2013-10-24T19:56:10.387 回答