以泛型方式调用静态方法

Static method call in generic manner

我有多个 class 喜欢:

public class Base { }
public class Base1: Base { public static List<Base1> LoadFromXml(string path) }
public class Base2: Base { public static List<Base2> LoadFromXml(string path) }

那么我想要一个这样的方法:

public List<T> PrepareBase<T>() where T: Base { return T.Load("C:\test.xml"); }

这样我就不必为每种类型都创建一个方法。 但是我不知道如何完成这个或类似的东西。

问题是我无法让基础 class 知道 LoadFromXml 方法,因为静态继承不是问题。使用静态方法创建单独的接口也不是。

有没有办法做到这一点,还是我期望过高?

编辑: LoadFromXml 方法的示例:

public class Base1 
{
    public int ID { get; set; }
    public string PropertyOnlyInBase1 { get; set; }
    public static List<Base1> LoadFromXml(string path)
    {
        List<Base1> baseList = new List<Base1>();
        XDocument doc = XDocument.Load(path);
        foreach(var node in doc.Descendants("Base1"))
        {
            Base 1 base = new Base1() { ID = node.Attributes["id"] };
            base.PropertyOnlyInBase1 = node.Element("PropertyOnlyInBase1");
            baseList.Add(base);
        }
        return baseList;
    }
}

所以 Base classes 也有一些独特的属性。这就是为什么我首先需要继承的原因。

我认为你是正确的,从 XML 加载这些的 class 应该与 正在加载 的 class 分开.正如你所说,它与实例没有真正的联系。

也许您需要一个单独的 class 来为您加载这些实例。

public class BaseXmlLoader<TBase> where TBase : Base
{
    public List<TBase> LoadFromXml(string filePath)
    {
        var serializer = new XmlSerializer(typeof(TBase));
        // Load your file and deserialize.
    }
}

好处不大,因为它并没有为您节省那么多代码。但是,如果 LoadFromXml 方法除了类型之外基本相同,那么您就会从中得到一些东西。

一个选项是添加 GenericBase:

public abstract class Base
{
}
public static class GenericBase<T>
    where T : Base
{
    public static List<T> LoadFromXml(string path)
    {
        //Load from XML
    }
}
public class Base1 : Base { }
public class Base2 : Base { }

public class Test //MainForm.cs class or whatever you want
{
    public void Tester() //Load event handler or whatever you want
    {
        List<Base1> base1List = PrepareBase<Base1>();
    }
    public List<T> PrepareBase<T>() where T : Base
    { return GenericBase<T>.LoadFromXml("C:\test.xml"); }
}

编辑:

D Stanley所述,这是不可能的;但我做了一些可能对你有帮助的解决方法:

public abstract class Base
{
    public static List<T> LoadFromXml<T>(string path) where T : Base, new()
    {
        List<T> baseList = new List<T>();
        XDocument doc = XDocument.Load(path);
        foreach (var node in doc.Descendants(typeof(T).Name))
        {
            T t = new T();
            Dictionary<string, string> d = new Dictionary<string, string>();
            foreach (var item in node.Elements())
                d.Add(item.Name.ToString(), item.Value);
            t.Load(d);
            baseList.Add(t);
        }
        return baseList;
    }

    protected internal abstract void Load(Dictionary<string, string> elements);
}
public class Base1 : Base
{
    public string CustomProp1 { get; set; }
    public string CustomProp2 { get; set; }
    public string CustomProp3 { get; set; }

    protected internal override void Load(Dictionary<string, string> elements)
    {
        if (elements.ContainsKey("CustomProp1"))
            CustomProp1 = elements["CustomProp1"];
        if (elements.ContainsKey("CustomProp2"))
            CustomProp2 = elements["CustomProp2"];
        if (elements.ContainsKey("CustomProp3"))
            CustomProp3 = elements["CustomProp3"];
    }
}
public class Base2 : Base
{
    public string CustomProp1 { get; set; }
    public string CustomProp2 { get; set; }
    public string CustomProp3 { get; set; }
    protected internal override void Load(Dictionary<string, string> elements)
    {
        if (elements.ContainsKey("CustomProp1"))
            CustomProp1 = elements["CustomProp1"];
        if (elements.ContainsKey("CustomProp2"))
            CustomProp2 = elements["CustomProp2"];
        if (elements.ContainsKey("CustomProp3"))
            CustomProp3 = elements["CustomProp3"];
    }
}

public class Test //MainForm.cs class or whatever you want
{
    public void Tester() //Load event handler or whatever you want
    {
        List<Base1> base1List = PrepareBase<Base1>();
    }
    public List<T> PrepareBase<T>() where T : Base, new()
    {
        return Base.LoadFromXml<T>("C:\test.xml");
    }
}

我改变了解决问题的方法并使用工厂模式解决了它。我还为每个 class 提供了一个实例方法 SetPropertiesFromXml 来处理自定义属性。与以前使用的方法不同,像这样的方法作为实例方法是有意义的。

工厂:

public static class BaseFactory 
{
    public static Base GetBase(string id) 
    { 
        switch(id) { case '1': return new Base1(); ... }
    }

    public static T GetBaseList<T>(string xml, string tagName) where T: Base
    {
        List<T> list = new List<T>();
        var nodes = XDocument.Load(xml).Descendants(tagName);
        foreach(XElement node in nodes)
        {
            var base = GetBase(node.Attribute("id").Value);
            base.SetPropertiesFromXml(node);
            list.Add(base as T);
        }
    }
}

基地

public abstract class Base
{
    public virtual void SetPropertiesFromXml(XElement node) 
    { 
        //<Set Properties like: this.Property = node.Element("key");>
    }
}

public class Base1
{
    public override void SetPropertiesFromXml(XElement node)
    {
        //<Set Custom Properties for Base1>

        //Call Base to add the normal properties as well
        base.SetPropertiesFromXml(node);
    }
}

通话

List<Base1> list = BaseFactory.GetBaseList<Base1>("test.xml", "Base1");