以泛型方式调用静态方法
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");
我有多个 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");