使用 LINQ 创建 List其中 T : someClass;

发布于 2024-12-16 17:05:52 字数 988 浏览 2 评论 0 原文

这与我之前的问题有关 C# 通用列表转换为实现 List 的类

我有以下代码:

public abstract class DataField
{
    public string Name { get; set; }
}

public class DataField<T> : DataField
{
    public T Value { get; set; }
}

public static List<DataField> ConvertXML(XMLDocument data) {  
     result = (from d in XDocument.Parse(data.OuterXML).Root.Decendendants()
                      select new DataField<string>
                      {
                          Name = d.Name.ToString(),
                          Value = d.Value
                      }).Cast<DataField>().ToList();  
    return result;
}

这可以工作,但是我希望能够将 LINQ 查询的选择部分修改为如下所示:

select new DataField<[type defined in attribute of XML Element]>
{
  Name = d.Name.ToString(),
  Value = d.Value
}

这只是一个糟糕的方法吗?是否可以?有什么建议吗?

This is related to a prior question of mine C# Generic List conversion to Class implementing List<T>

I have the following code:

public abstract class DataField
{
    public string Name { get; set; }
}

public class DataField<T> : DataField
{
    public T Value { get; set; }
}

public static List<DataField> ConvertXML(XMLDocument data) {  
     result = (from d in XDocument.Parse(data.OuterXML).Root.Decendendants()
                      select new DataField<string>
                      {
                          Name = d.Name.ToString(),
                          Value = d.Value
                      }).Cast<DataField>().ToList();  
    return result;
}

This works however I would like to be able to modify the select portion of the LINQ query to be something like this:

select new DataField<[type defined in attribute of XML Element]>
{
  Name = d.Name.ToString(),
  Value = d.Value
}

Is this just a poor approach? is it possible? Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

眼泪也成诗 2024-12-23 17:05:52

这是一个可行的解决方案:(您必须为 Type 属性指定完全限定的类型名称,否则您必须以某种方式配置映射...)

我使用了动态关键字,如果您没有,则可以使用反射来设置值C#4...

public static void Test()
{
    string xmlData = "<root><Name1 Type=\"System.String\">Value1</Name1><Name2 Type=\"System.Int32\">324</Name2></root>";

    List<DataField> dataFieldList = DataField.ConvertXML(xmlData);

    Debug.Assert(dataFieldList.Count == 2);
    Debug.Assert(dataFieldList[0].GetType() == typeof(DataField<string>));
    Debug.Assert(dataFieldList[1].GetType() == typeof(DataField<int>));
}

public abstract class DataField
{
    public string Name { get; set; }

    /// <summary>
    /// Instanciate a generic DataField<T> given an XElement
    /// </summary>
    public static DataField CreateDataField(XElement element)
    {
        //Determine the type of element we deal with
        string elementTypeName = element.Attribute("Type").Value;
        Type elementType = Type.GetType(elementTypeName);

        //Instanciate a new Generic element of type: DataField<T>
        dynamic dataField = Activator.CreateInstance(typeof(DataField<>).MakeGenericType(elementType));
        dataField.Name = element.Name.ToString();

        //Convert the inner value to the target element type
        dynamic value = Convert.ChangeType(element.Value, elementType);

        //Set the value into DataField
        dataField.Value = value;

        return dataField;
    }

    /// <summary>
    /// Take all the descendant of the root node and creates a DataField for each
    /// </summary>
    public static List<DataField> ConvertXML(string xmlData)
    {
        var result = (from d in XDocument.Parse(xmlData).Root.DescendantNodes().OfType<XElement>()
                      select CreateDataField(d)).ToList();

        return result;
    }
}

public class DataField<T> : DataField
{
    public T Value { get; set; }
}

Here is a working solution: (You must specify fully qualified type names for your Type attribute otherwise you have to configure a mapping somehow...)

I used the dynamic keyword, you can use reflection to set the value instead if you do not have C# 4...

public static void Test()
{
    string xmlData = "<root><Name1 Type=\"System.String\">Value1</Name1><Name2 Type=\"System.Int32\">324</Name2></root>";

    List<DataField> dataFieldList = DataField.ConvertXML(xmlData);

    Debug.Assert(dataFieldList.Count == 2);
    Debug.Assert(dataFieldList[0].GetType() == typeof(DataField<string>));
    Debug.Assert(dataFieldList[1].GetType() == typeof(DataField<int>));
}

public abstract class DataField
{
    public string Name { get; set; }

    /// <summary>
    /// Instanciate a generic DataField<T> given an XElement
    /// </summary>
    public static DataField CreateDataField(XElement element)
    {
        //Determine the type of element we deal with
        string elementTypeName = element.Attribute("Type").Value;
        Type elementType = Type.GetType(elementTypeName);

        //Instanciate a new Generic element of type: DataField<T>
        dynamic dataField = Activator.CreateInstance(typeof(DataField<>).MakeGenericType(elementType));
        dataField.Name = element.Name.ToString();

        //Convert the inner value to the target element type
        dynamic value = Convert.ChangeType(element.Value, elementType);

        //Set the value into DataField
        dataField.Value = value;

        return dataField;
    }

    /// <summary>
    /// Take all the descendant of the root node and creates a DataField for each
    /// </summary>
    public static List<DataField> ConvertXML(string xmlData)
    {
        var result = (from d in XDocument.Parse(xmlData).Root.DescendantNodes().OfType<XElement>()
                      select CreateDataField(d)).ToList();

        return result;
    }
}

public class DataField<T> : DataField
{
    public T Value { get; set; }
}
ㄟ。诗瑗 2024-12-23 17:05:52

在 C# 中无法轻松做到这一点。必须在编译时指定泛型类型参数。您可以使用反射来执行其他操作。

int X = 1;
Type listype = typeof(List<>);
Type constructed = listype.MakeGenericType(  X.GetType()  );
object runtimeList = Activator.CreateInstance(constructed);

这里我们刚刚创建了一个List。你可以用你的类型来做。

You cannot do this easily in C#. The generic type argument has to be specified at compile time. You can use reflection to do otherwise.

int X = 1;
Type listype = typeof(List<>);
Type constructed = listype.MakeGenericType(  X.GetType()  );
object runtimeList = Activator.CreateInstance(constructed);

Here we have just created a List<int>. You can do it with your type.

月下客 2024-12-23 17:05:52

泛型类的不同实例实际上是不同的类。
DataFieldDataField 根本不是同一个类(!)

这意味着,您不能在运行时定义通用参数,因为它必须在编译时确定。

Different instances of a generic class are actually different classes.
I.e. DataField<string> and DataField<int> are not the same class at all(!)

This means, that you can not define the generic parameter during run-time, as it has to be determined during compile-time.

溇涏 2024-12-23 17:05:52

我想说这是一个糟糕的方法。实际上,即使在解析 XML 文件之后,您也不会知道您拥有什么类型的“DataFields”。您不妨将它们解析为对象。

但是,如果您知道只会有 x 种类型,则可以这样做:

var Dictionary<string, Func<string, string, DataField>> myFactoryMaps =
{
    {"Type1", (name, value) => { return new DataField<Type1>(name, Type1.Parse(value); } },
    {"Type2", (name, value) => { return new DataField<Type2>(name, Type2.Parse(value); }  },
};

I would say this is a poor approach. In reality, even after you parse your XML file, you're not going to know what types of "DataFields" you have. You might as well just parse them as objects.

However, if you know that you're only ever going to have x number of types, you can do like so:

var Dictionary<string, Func<string, string, DataField>> myFactoryMaps =
{
    {"Type1", (name, value) => { return new DataField<Type1>(name, Type1.Parse(value); } },
    {"Type2", (name, value) => { return new DataField<Type2>(name, Type2.Parse(value); }  },
};
一紙繁鸢 2024-12-23 17:05:52

特米特的回答当然非常好。这是一个小变体。

     public abstract class DataField
        {
                public string Name { get; set; }
        }

        public class DataField<T> : DataField
        {
                public T Value { get; set; }
                public Type GenericType { get { return this.Value.GetType(); } }
        }

        static Func<XElement , DataField> dfSelector = new Func<XElement , DataField>( e =>
        {
                string strType = e.Attribute( "type" ).Value;
                //if you dont have an attribute type, you could call an extension method to figure out the type (with regex patterns)
                //that would only work for struct
                Type type = Type.GetType( strType );
                dynamic df = Activator.CreateInstance( typeof( DataField<>).MakeGenericType( type ) );

                df.Name = e.Attribute( "name" ).Value;
                dynamic value = Convert.ChangeType( e.Value , type );
                df.Value = value;
                return df;
        } );

        public static List<DataField> ConvertXML( string xmlstring )
        {
                var result = XDocument.Parse( xmlstring )
                                        .Root.Descendants("object")
                                        .Select( dfSelector )
                                        .ToList();
                return result;
        }


        static void Main( string[] args )
        {
                string xml = "<root><object name=\"im1\" type=\"System.String\">HelloWorld!</object><object name=\"im2\" type=\"System.Int32\">324</object></root>";

                List<DataField> dfs = ConvertXML( xml );
        }

Termit's answer is certainly excellent. Here is a little variant.

     public abstract class DataField
        {
                public string Name { get; set; }
        }

        public class DataField<T> : DataField
        {
                public T Value { get; set; }
                public Type GenericType { get { return this.Value.GetType(); } }
        }

        static Func<XElement , DataField> dfSelector = new Func<XElement , DataField>( e =>
        {
                string strType = e.Attribute( "type" ).Value;
                //if you dont have an attribute type, you could call an extension method to figure out the type (with regex patterns)
                //that would only work for struct
                Type type = Type.GetType( strType );
                dynamic df = Activator.CreateInstance( typeof( DataField<>).MakeGenericType( type ) );

                df.Name = e.Attribute( "name" ).Value;
                dynamic value = Convert.ChangeType( e.Value , type );
                df.Value = value;
                return df;
        } );

        public static List<DataField> ConvertXML( string xmlstring )
        {
                var result = XDocument.Parse( xmlstring )
                                        .Root.Descendants("object")
                                        .Select( dfSelector )
                                        .ToList();
                return result;
        }


        static void Main( string[] args )
        {
                string xml = "<root><object name=\"im1\" type=\"System.String\">HelloWorld!</object><object name=\"im2\" type=\"System.Int32\">324</object></root>";

                List<DataField> dfs = ConvertXML( xml );
        }
黯淡〆 2024-12-23 17:05:52

您可以通过反射创建泛型类型

    var instance = Activator.CreateInstance( typeof(DataField)
                         .MakeGenericType(Type.GetType(typeNameFromAttribute) );
    // and here set properties also by reflection

you can create generic type by reflection

    var instance = Activator.CreateInstance( typeof(DataField)
                         .MakeGenericType(Type.GetType(typeNameFromAttribute) );
    // and here set properties also by reflection
月亮是我掰弯的 2024-12-23 17:05:52

@Termit 和 @Burnzy 提出了涉及工厂方法的良好解决方案。

这样做的问题是,您正在为可疑的返回加载大量额外的逻辑(更多测试,更多错误)的解析例程。

另一种方法是使用带有类型读取方法的简化的基于字符串的 DataField -

类型化值方法的实现,该方法很好,但仅适用于值类型(不包括字符串,但包括日期时间):

public T? TypedValue<T>()
    where T : struct
{
    try { return (T?) Convert.ChangeType(this.Value, typeof(T)); }
    catch { return null; }
}

我假设你想要使用类型信息来做一些事情,比如动态地将用户控件分配给字段、验证规则、正确的 SQL 类型以实现持久性等。

我已经用方法做了很多这样的事情这看起来有点像你的。

归根结底,您应该将元数据与代码分开 - @Burnzy 的答案根据元数据(DataField 元素的“type”属性)选择代码,这是一个非常简单的示例。

如果您正在处理 XML,XSD 是一种非常有用且可扩展的元数据形式。

至于您存储每个字段的数据的内容 - 使用字符串,因为:

  • 它们可以为空
  • 他们可以存储部分值
  • 他们可以存储无效值(让告诉用户对他们的行为进行排序更加透明)
  • 他们可以存储列表
  • 特殊情况不会侵入不相关的代码,因为没有任何
  • 学习正则表达式,验证,很高兴
  • 你可以很容易地将它们转换为更强的类型

我发现开发这样的小框架非常有价值 - 这是一种学习经历,你会明白更多关于用户体验和现实的内容从中建模。

我建议您首先处理四组测试用例:

  • 日期、时间、时间戳(我称之为日期时间)、周期(时间跨度)
    • 特别是,请确保您测试的服务器位置与客户端的服务器位置不同。
  • 列表 - 多选外键等
  • 空值
  • 无效输入 - 这通常涉及保留原始值

使用字符串可以大大简化这一切,因为它允许您在框架内清楚地划分职责。考虑一下在通用模型中执行包含列表的字段 - 它很快就会变得很复杂,并且很容易在几乎每种方法中都出现列表的特殊情况。有了弦,责任就到此为止了。

最后,如果您希望在无需执行任何操作的情况下可靠地实现此类内容,请考虑 数据集 - 我知道老派 - 它们可以做各种你意想不到的奇妙事情,但你必须使用 RTFM。

这个想法的主要缺点是它与 WPF 数据绑定不兼容 - 尽管我的经验是现实与 WPF 数据绑定不兼容。

我希望我正确地理解了你的意图 - 不管怎样,祝你好运:)

@Termit and @Burnzy put forward good solutions involving factory methods.

The problem with that is that you're loading up your parsing routine with a bunch of extra logic (more testing, more errors) for dubious returns.

Another way to do it would be to use a simplified string-based DataField with typed read methods - the top answer for this question.

An implementation of a typed-value method that would be nice but only works for value types (which does not include strings but does include DateTimes):

public T? TypedValue<T>()
    where T : struct
{
    try { return (T?) Convert.ChangeType(this.Value, typeof(T)); }
    catch { return null; }
}

I'm assuming that you're wanting to use the type information to do things like dynamically assigning user-controls to the field, validation rules, correct SQL types for persistence etc.

I've done a lot of this sort of thing with approaches that seem a bit like yours.

At the end of the day you should seperate your metadata from your code - @Burnzy's answer chooses the code based on the metadata (a "type" attribute of the DataField element) and is a very simple example of this.

If you're dealing with XML, XSDs are a very useful and extensible form of metadata.

As far as what you store each field's data in - use strings because:

  • they are nullable
  • they can store partial values
  • they can store invalid values (makes telling the user to sort their act out more transparent)
  • they can store lists
  • special cases won't invade unrelated code because there aren't any
  • learn regular expressions, validate, be happy
  • you can convert them to stronger types really easily

I found it very rewarding to develop little frameworks like this - it is a learning experience and you'll come out understanding a lot more about UX and the reality of modelling from it.

There are four groups of test cases that I would advise you to tackle first:

  • Dates, Times, Timestamps (what I call DateTime), Periods (Timespan)
    • in particular, make sure you test having a different server locality from the client's.
  • lists - multi-select foreign keys etc
  • null values
  • invalid input - this generally involves retaining the original value

Using strings simplifies all this greatly because it allows you to clearly demarcate responsibilities within your framework. Think about doing fields containing lists in your generic model - it gets hairy rather quickly and it is easy to end up with a special case for lists in pretty much every method. With strings, the buck stops there.

Finally, if you want a solid implementation of this sort of stuff without having to do anything much, consider DataSets - old school I know - they do all sorts of wonderful things you wouldn't expect but you do have to RTFM.

The main downfall of that idea would be that it isn't compatible with WPF data binding - though my experience has been that reality isn't compatible with WPF data binding.

I hope I interpreted your intentions correctly - good luck either way :)

帅气称霸 2024-12-23 17:05:52

不幸的是,例如,CC 之间没有继承关系。
但是,您可以从常见的非泛型类继承,此外还可以实现泛型接口。
在这里,我使用显式接口实现,以便能够声明类型为对象的 Value 属性,以及更具体类型的 Value 属性。
这些值是只读的,只能通过类型化构造函数参数进行分配。我的构造并不完美,但类型安全并且不使用反射。

public interface IValue<T>
{
    T Value { get; }
}

public abstract class DataField
{
    public DataField(string name, object value)
    {
        Name = name;
        Value = value;
    }
    public string Name { get; private set; }
    public object Value { get; private set; }
}

public class StringDataField : DataField, IValue<string>
{
    public StringDataField(string name, string value)
        : base(name, value)
    {
    }

    string IValue<string>.Value
    {
        get { return (string)Value; }
    }
}

public class IntDataField : DataField, IValue<int>
{
    public IntDataField(string name, int value)
        : base(name, value)
    {
    }

    int IValue<int>.Value
    {
        get { return (int)Value; }
    }
}

然后可以使用抽象基类 DataField 作为泛型参数来声明该列表:

var list = new List<DataField>();
switch (fieldType) {
    case "string":
        list.Add(new StringDataField("Item", "Apple"));
        break;
    case "int":
        list.Add(new IntDataField("Count", 12));
        break;
}

通过接口访问强类型字段:

public void ProcessDataField(DataField field)
{
    var stringField = field as IValue<string>;
    if (stringField != null) {
        string s = stringField.Value;
    }
}

Unfortunately, there no inheritance relation between C<T> and C<string> for instance.
However, you can inherit from a common non-generic class and in addition to this implement a generic interface.
Here I use explicit interface implementation in order to be able to declare a Value property typed as object, as well as a more specifically typed Value property.
The Values are read-only and can only be assigned through a typed constructor parameter. My construction is not perfect, but type safe and doesn't use reflection.

public interface IValue<T>
{
    T Value { get; }
}

public abstract class DataField
{
    public DataField(string name, object value)
    {
        Name = name;
        Value = value;
    }
    public string Name { get; private set; }
    public object Value { get; private set; }
}

public class StringDataField : DataField, IValue<string>
{
    public StringDataField(string name, string value)
        : base(name, value)
    {
    }

    string IValue<string>.Value
    {
        get { return (string)Value; }
    }
}

public class IntDataField : DataField, IValue<int>
{
    public IntDataField(string name, int value)
        : base(name, value)
    {
    }

    int IValue<int>.Value
    {
        get { return (int)Value; }
    }
}

The list can then be declared with the abstract base class DataField as generic parameter:

var list = new List<DataField>();
switch (fieldType) {
    case "string":
        list.Add(new StringDataField("Item", "Apple"));
        break;
    case "int":
        list.Add(new IntDataField("Count", 12));
        break;
}

Access the strongly typed field through the interface:

public void ProcessDataField(DataField field)
{
    var stringField = field as IValue<string>;
    if (stringField != null) {
        string s = stringField.Value;
    }
}
新人笑 2024-12-23 17:05:52

虽然其他问题大多提出了一个优雅的解决方案来将 XML 元素转换为通用类实例,但我将处理采用该方法将 DataField 类建模为通用类(例如 DataField<[type Defined] 的方法)的后果。在 XML 元素的属性中]>

将 DataField 实例选择到列表中后,您要使用这些字段。她的多态性发挥作用了!您想要迭代您的数据字段并以统一的方式处理它们。使用泛型的解决方案通常会陷入奇怪的 switch/if 狂欢中,因为没有简单的方法来根据 C# 中的泛型类型关联行为。

您可能见过这样的代码(我正在尝试计算所有数字 DataField 实例的总和)

var list = new List<DataField>()
{
    new DataField<int>() {Name = "int", Value = 2},
    new DataField<string>() {Name = "string", Value = "stringValue"},
    new DataField<float>() {Name = "string", Value = 2f},
};

var sum = 0.0;

foreach (var dataField in list)
{
    if (dataField.GetType().IsGenericType)
    {
        if (dataField.GetType().GetGenericArguments()[0] == typeof(int))
        {
            sum += ((DataField<int>) dataField).Value;
        }
        else if (dataField.GetType().GetGenericArguments()[0] == typeof(float))
        {
            sum += ((DataField<float>)dataField).Value;
        }
        // ..
    }
}

此代码完全是一团糟!

让我们尝试使用泛型类型 DataField 进行多态实现,并向其中添加一些方法 Sum ,该方法接受旧的 sum 并返回(可能已修改)新的 sum:

public class DataField<T> : DataField 
{
    public T Value { get; set; }
    public override double Sum(double sum)
    {
       if (typeof(T) == typeof(int))
       {
           return sum + (int)Value; // Cannot really cast here!
       }
       else if (typeof(T) == typeof(float))
       {
           return sum + (float)Value; // Cannot really cast here!
       }
       // ...

       return sum;
    }
}

你可以想象你的迭代代码会得到很多现在更清楚了,但代码中仍然有这个奇怪的 switch/if 语句。重点是:泛型在这里并不能帮助你,它是在错误的地方使用了错误的工具。泛型是用 C# 设计的,旨在为您提供编译时类型安全性,以避免潜在的不安全强制转换操作。它们还增加了代码的可读性,但这里的情况并非如此:)

让我们看一下多态解决方案:

public abstract class DataField
{
    public string Name { get; set; }
    public object Value { get; set; }
    public abstract double Sum(double sum);
}

public class IntDataField : DataField
{
    public override double Sum(double sum)
    {
        return (int)Value + sum;
    }
}

public class FloatDataField : DataField
{
    public override double Sum(double sum)
    {
        return (float)Value + sum;
    }
}

我想您不需要太多的幻想来想象对代码的可读性/质量增加了多少。

最后一点是如何创建这些类的实例。只需使用一些约定 TypeName +“DataField”和 Activator:

Activator.CreateInstance("assemblyName", typeName);

简短版本

泛型不是解决您的问题的适当方法,因为它不会为 DataField 实例的处理增加价值。通过多态方法,您可以轻松地使用 DataField 的实例!

While the other questions mostly proposed an elegant solution to convert your XML elements to a generic class instance, I'm going to deal with the consequences of taking the approach to model the DataField class as a generic like DataField<[type defined in attribute of XML Element]>.

After selecting your DataField instance into the list you want to use these fields. Her polymorphism comes into play! You want to iterate your DataFields an treat them in a uniform way. Solutions that use generics often end up in a weird switch/if orgy since there is no easy way to associate behavior based on the generic type in c#.

You might have seen code like this (I'm trying to calculate the sum of all numeric DataField instances)

var list = new List<DataField>()
{
    new DataField<int>() {Name = "int", Value = 2},
    new DataField<string>() {Name = "string", Value = "stringValue"},
    new DataField<float>() {Name = "string", Value = 2f},
};

var sum = 0.0;

foreach (var dataField in list)
{
    if (dataField.GetType().IsGenericType)
    {
        if (dataField.GetType().GetGenericArguments()[0] == typeof(int))
        {
            sum += ((DataField<int>) dataField).Value;
        }
        else if (dataField.GetType().GetGenericArguments()[0] == typeof(float))
        {
            sum += ((DataField<float>)dataField).Value;
        }
        // ..
    }
}

This code is a complete mess!

Let's go try the polymorphic implementation with your generic type DataField and add some method Sum to it that accepts the old some and returns the (possibly modified) new sum:

public class DataField<T> : DataField 
{
    public T Value { get; set; }
    public override double Sum(double sum)
    {
       if (typeof(T) == typeof(int))
       {
           return sum + (int)Value; // Cannot really cast here!
       }
       else if (typeof(T) == typeof(float))
       {
           return sum + (float)Value; // Cannot really cast here!
       }
       // ...

       return sum;
    }
}

You can imagine that your iteration code gets a lot clearer now but you still have this weird switch/if statement in you code. And here comes the point: Generics do not help you here it's the wrong tool at the wrong place. Generics are designed in C# for giving you compile time type safety to avoid potential unsafe cast operations. They additionally add to code readability but that's not the case here :)

Let's take a look at the polymorphic solution:

public abstract class DataField
{
    public string Name { get; set; }
    public object Value { get; set; }
    public abstract double Sum(double sum);
}

public class IntDataField : DataField
{
    public override double Sum(double sum)
    {
        return (int)Value + sum;
    }
}

public class FloatDataField : DataField
{
    public override double Sum(double sum)
    {
        return (float)Value + sum;
    }
}

I guess you will not need too much fantasy to imagine how much adds to your code's readability/quality.

The last point is how to create instances of these classes. Simply by using some convention TypeName + "DataField" and Activator:

Activator.CreateInstance("assemblyName", typeName);

Short Version:

Generics is not the appropriate approach for your problem because it does not add value to the handling of DataField instances. With the polymorphic approach you can work easily with the instances of DataField!

笑叹一世浮沉 2024-12-23 17:05:52

这并非不可能,因为你可以通过反思来做到这一点。但这不是泛型的设计目的,也不是它应该的实现方式。如果您打算使用反射来创建泛型类型,那么您也可以根本不使用泛型类型,而只使用以下类:

public class DataField
{
    public string Name { get; set; }
    public object Value { get; set; }
}

It's not impossible as you can do this with reflection. But this isn't what generics were designed for and isn't how it should be done. If you're going to use reflection to make the generic type, you may as well not use a generic type at all and just use the following class:

public class DataField
{
    public string Name { get; set; }
    public object Value { get; set; }
}
白况 2024-12-23 17:05:52

您需要插入用于从 XML 确定数据类型的逻辑,并添加您需要使用的所有类型,但这应该可行:

            result = (from d in XDocument.Parse(data.OuterXML).Root.Descendants()
                      let isString = true //Replace true with your logic to determine if it is a string.
                      let isInt = false   //Replace false with your logic to determine if it is an integer.
                      let stringValue = isString ? (DataField)new DataField<string>
                      {
                          Name = d.Name.ToString(),
                          Value = d.Value
                      } : null
                      let intValue = isInt ? (DataField)new DataField<int>
                      {
                          Name = d.Name.ToString(),
                          Value = Int32.Parse(d.Value)
                      } : null
                      select stringValue ?? intValue).ToList();

You'll need to insert the logic for determining the data type from your XML and add all the types you need to use but this should work:

            result = (from d in XDocument.Parse(data.OuterXML).Root.Descendants()
                      let isString = true //Replace true with your logic to determine if it is a string.
                      let isInt = false   //Replace false with your logic to determine if it is an integer.
                      let stringValue = isString ? (DataField)new DataField<string>
                      {
                          Name = d.Name.ToString(),
                          Value = d.Value
                      } : null
                      let intValue = isInt ? (DataField)new DataField<int>
                      {
                          Name = d.Name.ToString(),
                          Value = Int32.Parse(d.Value)
                      } : null
                      select stringValue ?? intValue).ToList();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文