【问题标题】:Access to property of inherited generic class访问继承的泛型类的属性
【发布时间】:2019-03-08 20:16:09
【问题描述】:

基于这个话题:C# - Multiple generic types in one list

请考虑以下代码:

public abstract class Metadata
{
}

public class Metadata<T> : Metadata
{
    public string Name {set; get;}
}

public class MetaDataCollection
{
    public void DoSomeThing()
    {
        List<Metadata> metadataObjects = new List<Metadata>
        {
            new Metadata<int>() { Name = "Name 1"},
            new Metadata<bool>() { Name = "Name 2"},
            new Metadata<double>() { Name = "Name 3"},
        };

        foreach(vat item in metadataObjects)
        {
            item.Name ??????
        }
    }
}

在上面的代码中,我如何访问Name 属性?

谢谢

编辑 1)

感谢@BWA。但我有一个通用属性:

public class Metadata<T> : Metadata
{
    public override string Name {set; get;}

    public List<T> Some {set; get;} <-----
}

我不能在基本抽象类中声明它。对于那个属性,我能做什么?

【问题讨论】:

  • 将该属性拉到Metadata 并让Metadata&lt;T&gt; 继承它。或者将Metadata 转换为具有Name 属性的接口。现在,MetadataMetadata&lt;T&gt; 无关
  • 你不能,因为Metadata 没有那个属性。与其向multiple (duplicate) questions 询问同样的问题,不如尝试正确解释您正在尝试做的事情。
  • 顺便说一句,这与 C# 7 或泛型无关,它只是继承
  • @Arian 如果您可以发布单独的问题而不是将您的问题合并为一个问题,则最好。这样,它可以帮助人们回答您的问题,也可以帮助其他人至少寻找您的一个问题。谢谢!

标签: c#


【解决方案1】:

您的代码无法编译。

Metadata, Metadata<T>, Metadata<int> ...

每个都是不同的类型。泛型类型不是继承。你不能这样做。

你可以这样做:

using System.Collections.Generic;

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

public class Metadata<T> : Metadata
{
    public override string Name {set; get;}
}

public class MetaDataCollection
{
    public void DoSomeThing()
    {
        List<Metadata> metadataObjects = new List<Metadata>
        {
            new Metadata<int>() { Name = "Name 1"},
            new Metadata<bool>() { Name = "Name 2"},
            new Metadata<double>() { Name = "Name 3"},
        };

        foreach(Metadata item in metadataObjects)
        {
            string s = item.Name;
        }
    }
}

首先Metadata&lt;T&gt; 必须继承自Metadata。然后继承就可以工作了。

【讨论】:

  • @BWA :请参阅:C# - 一个列表中的多个泛型类型
  • @BWA:一个不错的解决方案。
  • @Arian 您链接的问题与您提出的问题无关。这是关于继承,而不是泛型
  • 如@PanagiotisKanavos 所说。一个问题。
  • @Arian 我认为答案是here
【解决方案2】:

现在,元数据和元数据是不相关的。它们没有继承关系,只是名称相似。

一种选择是将Name 属性拉到元数据并让元数据从它继承:

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

public class Metadata<T>:Metadata
{
    //public string Name {set; get;}
}

另一种选择是将Metadata 转换为具有Name 属性的接口:

public interface IMetadata
{
    string Name {set; get;}
}

public class Metadata<T>:IMetadata
{
    public string Name {set; get;}
}

更改测试代码以使用正确的基类,例如:

{
    var metadataObjects = new List<Metadata>
    {
        new Metadata<int>() { Name = "Name 1"},
        new Metadata<bool>() { Name = "Name 2"},
        new Metadata<double>() { Name = "Name 3"},
    };

    var metadataObjects = new List<IMetadata>
    {
        new Metadata<int>() { Name = "Name 1"},
        new Metadata<bool>() { Name = "Name 2"},
        new Metadata<double>() { Name = "Name 3"},
    };

在这两种情况下,循环保持不变:

    foreach(var item in metadataObjects)
    {
        Console.WriteLine(item.Name);
    }

【讨论】:

  • @Arian 这是一个不同的问题。请发布一个,完成问题。
  • 是的,你是对的。但是对不起,我想忘记泛型属性
  • 发布一个不同的问题。这个已经回答了。事实上,除非你想在循环中使用Some,否则泛型属性无关紧要。
  • @Arian 或者更确切地说,解释你真正想要做什么,而不是你如何尝试实现它。 DataTables 有元数据,Entity Framework 也有。您可以重用他们的技术,甚至直接使用元数据类
  • @Arian 检查 MVC 中的 HTML Helpers 或 EF 中的模型配置类如何工作。您将 表达式 作为参数传递,帮助程序或模型构建器可以使用该参数来查找您要显示或配置的属性。一旦他们这样做了,他们就可以检查任何数据注释属性,例如DisplayAttribute
【解决方案3】:

如果这是你想要的,我不知道,但它会给你你要求的结果。

public class Metadata
{
   public Type type { get; set; }
   public string Name { set; get; }
}

public class MetaDataCollection
{
   public void DoSomeThing()
   {
      List<Metadata> metadataObjects = new List<Metadata>
      {
         new Metadata() { Name = "Name 1", type = typeof(int)},
         new Metadata() { Name = "Name 2", type = typeof(bool)},
         new Metadata() { Name = "Name 3", type = typeof(double)},
      };

      foreach (Metadata item in metadataObjects)
      {
         item.Name..
      }
   }
}

【讨论】:

    最近更新 更多