我需要使用如下代码从通用列表中返回一个genericList templateFields
,如下所示:
public interface TestData
{
string field { get; set; }
string fieldName { get; set; }
string type { get; set; }
}
private static IList<T> GETCG<T>(string test, string type) where T : Program.TestData
{
XmlNodeList extractNode = xdoc.SelectNodes(
@".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
var templateFields = nodees.Cast<XmlNode>().Select(x => new
{
field = (String)x.Attributes["userName"].Value,
fieldName = (String)x.Attributes["name"].Value
.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
.IndexOf(':') + 1, 4)
}).ToList();
}
return (T)Convert.ChangeType(templateFields, typeof(T));
返回时出现以下错误:
对象必须实现Iconvertible。
我确实知道templateFields
并未实现IConvertible以使用ChangeType。什么是回归的最佳途径templateFields
答案 0 :(得分:1)
将new()
约束添加到T
并使用以下代码
private static IList<T> GETCG<T>(string test, string type) where T : TestData, new()
{
XmlNodeList extractNode = xdoc.SelectNodes(@".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
var templateFields = nodees.Cast<XmlNode>().Select(x => new T() //not anonymous type but T object
{
field = x.Attributes["userName"].Value,
fieldName = (string)x.Attributes["name"].Value.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
type = x.Attributes["name"].Value.Substring(x.Attributes["name"].Value.IndexOf(':') + 1, 4)
}).ToList();
return templateFields;
}
答案 1 :(得分:0)
我认为这里的问题是,您在进行select new { ... }
时选择了一个匿名类型,然后Convert.ChangeType
失败了,因为匿名类型仅包含public read-only
属性,而没有实施IConvertible
。相反,我们要选择一个新的T
。但是,为此,我们还必须在T
上包含一个new() constraint,这意味着T
必须具有默认构造函数(以便我们可以创建它的实例)。 / p>
通过此操作,我们无需进行任何转换,因为List<T>
导致Select
。
您还可以通过在一行中选择一个IEnumerable<XmlNode>
来减少某些代码,而不是创建第二个变量并在第一个变量上执行cast
。
类似的事情应该起作用:
private static IList<T> GETCG<T>(string test, string type) where T : TestData, new()
{
IEnumerable<XmlNode> templateFieldNodes = xdoc
.SelectNodes(".//mediaInstances/mediaInstance/properties/templateFields/templateField",
manager)
.Cast<XmlNode>();
return templateFieldNodes.Select(x => new T
{
field = (String)x.Attributes["userName"].Value,
fieldName = (String)x.Attributes["name"].Value
.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
.IndexOf(':') + 1, 4)
}).ToList();
}
答案 2 :(得分:0)
您声明的接口TestData
,但没有声明任何类型实现它。您不能将偶然碰巧具有相同属性的任何类型强制转换为该接口。您必须创建一个类或实现它的结构。另外,使用通常的.NET命名约定,接口名称以大写I
开头,属性名称带有PascalCase。
有了这些声明...
public interface ITestData
{
string Field { get; set; }
string FieldName { get; set; }
string Type { get; set; }
}
public class TestData : ITestData
{
public string Field { get; set; }
public string FieldName { get; set; }
public string Type { get; set; }
}
你可以写
private static IList<ITestData> GETCG(string test, string type)
{
XmlNodeList extractNode = xdoc.SelectNodes(
@".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
var templateFields = nodees.Cast<XmlNode>().Select(x => (ITestData)new TestData {
Field = (String)x.Attributes["userName"].Value,
FieldName = (String)x.Attributes["name"].Value
.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
Type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
.IndexOf(':') + 1, 4)
}).ToList();
return templateFields;
}
请注意,该方法不是通用的。要使.ToList()
创建一个IList<ITestData>
,必须将新数据强制转换为接口(ITestData)new TestData { ... }
。
现在的问题是,你是否还需要接口,或者如果你喜欢直接使用类。
如果您仍然希望方法是通用的,则必须告诉它T
必须具有带有new()
约束的默认构造函数。并且必须使用具体类型来调用该方法。即,你不能用接口调用它,因为这其中没有一个构造函数。
private static IList<T> GETCG<T>(string test, string type)
where T : ITestData, new()
{
...
var templateFields = nodees.Cast<XmlNode>().Select(x => new T {
...
}).ToList();
return templateFields;
}
并致电
IList<TestData> var result = GETCG<TestData>("hello", "world");