【问题标题】:C# Generic ListsC# 通用列表
【发布时间】:2009-02-18 21:49:57
【问题描述】:

我有一个类映射到数据库中的一个字段。该类只关心字段的名称及其相关的 .NET 类型。 类型可以是string、int、datetime等

class Foo()
{
    string Name { get; set; }
    Type FooType { get; set; }
}

我有另一个继承自 Foo 的类,它为一个值添加了一个属性。现在我将值存储为一个对象,并使用 switch 语句根据基类 FooType 将值装箱。

class FooWithStuff() : Foo
{
    object Value { get; set; }   
}

有没有办法用泛型来实现这一点,为值提供类型安全?

编辑:我已将关键要求加粗。当声明一个列表说 Foo 它需要一个类型。如果我针对自定义类执行此操作,我将创建和接口并使用它。但是这里我使用的是 int、string、DateTime 等。Int 是一个结构,string 是一个对象,所以 Foo 对两者都不起作用。

【问题讨论】:

    标签: c# generics


    【解决方案1】:
    class Foo
    {
        public string Name { get; set; }
        public Type Type { get; set; }
    }
    
    class Bar<T> : Foo
    {
        public T Value { get; set; }
    
        public Bar()
        {
            base.Type = typeof( T );
        }
    }
    

    【讨论】:

      【解决方案2】:

      这样定义你的类:

      class Foo<T> : IFoo
      {
      
          public Foo(string name)
          {
              Name = name;
          }
      
          string Name { get; set; }
          T Value {get; set;}
          Type FooType { get { return typeof(T); } }
      }
      

      然后您可以将接口 IFoo 定义为:

      string Name { get; set; }
      Type FooType { get; set; }
      

      并将列表声明为:

      List<IFoo> list = new List<IFoo>();
      

      【讨论】:

      • 这看起来是最完整、最准确、最干净的实现。我目前正在尝试。
      【解决方案3】:

      如果您想为 Foo 添加 Value 并让 Foo 成为泛型,您可以这样做...

      class Foo<T>
      {
          T Value {get; set;}
      }
      
      Foo<int> myFoo = new Foo<int>();
      myFoo.Value = 7;
      

      【讨论】:

      • 但这不会满足 T 与 FooType 类型相同的附加约束?
      • 你不会再存储 FooType 了:你可以调用 Foo.GetType().GetGenericArguments[0]
      • 或者创建一个返回的属性: public Type FooType { get { return typeof(T); } }
      • 我想这就是我想要的,如果你有这种类型,我认为不需要 FooType。如果您仍想转换为基础,您可以实现 Foo 接口,我将发布一个示例。
      【解决方案4】:

      我会使用接口而不是通用类继承。

      编辑:澄清。我会为 Foo 使用一个接口,为 FooWithStuff 使用一个泛型类:

      public interface IFoo
      {
        string Name{get;set;}
        Type FooType{get;set;}
      }
      
      public class FooWithStuff<T>:IFoo
      {
         T Value {get;set;}
      }
      

      【讨论】:

      • 为什么要在界面上保留Type,转换不需要它?
      • 我想我没抓住重点。 @divo,是的,我对此做了很多假设。
      【解决方案5】:

      是的,事实上你可以简单地取消你的继承权..

      public class Foo<T>
      {
        public string Name {get;set;}
        public T Value {get;set;}
        public Type FooType
        {
           get
           {
             return typeof(T);
           }
        }
      }
      

      另请注意,使用 linq 您可以直接从列表中提取所需的类型,因此如果您出于某种原因只对字符串字段感兴趣,您可以...

      List<object> list = getAllmyFoos();
      foreach(Foo<string> sfoo in list.OfType<Foo<string>>())
      {
        ...blah
      }
      

      编辑:添加 FooType。

      【讨论】:

      • 问题是当我声明 List 它需要一个类型,它存储整数、字符串和日期时间等
      • 当然。如果你需要它,你需要它。
      【解决方案6】:

      我会推荐使用 2 个接口:

      public interface IFoo
      {
        string Name {get; }
        Type Type { get; }
        object Value {get; set;}
      }
      
      public interface IFoo<T> : IFoo
      {
        T Value {get; set}
      }
      

      然后实现它:

      public class Foo<T> : IFoo<T>
      {
         private T value;
         public Foo(string name, T value)
         {
           this.name = name;
           this.value = value;
         }
      
         public string Name { get { return name; } }
         public Type Type { get { return typeof(T); } }
         public T Value
         {
            get { return value; }
            set { value = value; }
         }
      
         object IFoo.Value
         {
            get { return value; }
            set { value = (T)value; }  // can check type before
         }
      }
      

      这样,您也可以在非通用上下文中轻松使用 IFoo 接口。

      【讨论】:

        猜你喜欢
        • 2011-01-30
        • 1970-01-01
        • 2011-05-15
        • 2011-02-14
        • 1970-01-01
        • 1970-01-01
        • 2011-08-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多