【问题标题】:How to access Property of generic member in generic class [duplicate]如何访问泛型类中泛型成员的属性[重复]
【发布时间】:2017-01-03 08:04:17
【问题描述】:

我是 C# 的新手。我正在尝试创建一个通用类。我有三个类和一个 Main/Generic 类。

三类

public class A
{
    public string Name { get; set; }
    public string Address { get; set; }

    public A(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }        
}

public class B
{
    public string Name { get; set; }
    public string Address { get; set; }

    public B(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }
}

public class C
{
    public string Name { get; set; }
    public string Address { get; set; }

    public C(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }
}

通用类

public class GenericClass<T>
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }

}

我已经成功创建了一个 Generic 类。

class Program
{
    static void Main(string[] args)
    {
        A objA = new A("Mohit", "India");
        GenericClass<A> objGenericClass = new GenericClass<A>(objA);

        Console.ReadLine();
    }

}

现在,如果我需要在 Generic 类中使用 Class A/B/C 属性。我该如何使用它?我知道类引用类型决定运行时。所以,我不能以下面的方式使用它。但是,还有其他方法吗?

public class GenericClass<T>
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }


    public void UseClassPro()
    {
        Console.WriteLine("Address " + DynamicObject.Address);//Compile time error here.
    }

}

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    其他答案是对的,但是...

    我只想指出:虽然其他答案促进了有效的 C# 代码,但它们使您实现的通用方面变得多余。你不再需要泛型了:

    给定一个基类或接口,如

    public interface IHasAddress
    {
        string Address { get; }
    }
    

    您不再需要 Generic 类来实现您想要实现的目标(从我可以通过您提供的代码得知):

    public class NotSoGenericClass
    {
        public GenericClass(IHasAddress obj)
        {
            DynamicObject = obj;
        }
    
        public IHasAddress DynamicObject { get; set; }    
    }
    

    如您所见,无需泛型即可轻松实现所需的行为。

    对于初学者,我推荐以下关于泛型的基本规则:

    1. 当您认为必须使用泛型时,强迫自己首先考虑通过接口、抽象类或基类进行抽象。这通常会带来更简单、更清洁的解决方案。
    2. 反射也是如此。当您认为需要反射时,请考虑泛型(此时规则 1 有效)

    但是泛型没有什么问题,只是更复杂,而且通常不需要。将上面的类与通用解决方案进行比较:

    public class GenericClass<T> where T : IHasAddress  // just for the sake of generics
    {
        public GenericClass(T obj)
        {
            DynamicObject = obj;
        }
    
        public T DynamicObject { get; set; }    
    }
    

    看起来更复杂,并没有增加任何好处,是吗?另请注意,无论如何您都需要一个接口/基类。否则,您也可以使用反射(不推荐)。

    真正回答您的问题

    您的问题的准确答案是:

    你必须定义你的泛型参数必须可以分配给IHasAddress 使用

    public class GenericClass<T> where T : IHasAddress
                                 ^^^^^^^^^^^^^^^^^^^^^
                                      This Part
    

    这样,编译器知道T 继承或属于IHasAddress 类型或您定义的任何类型。你也可以在这个地方传递多种类型,这在设计你的界面时增加了更多的灵活性。

    也许,从您在问题中提供的信息来看,您的用例中有些要点并不明显。在这种情况下,请随意添加一些细节,我也很乐意深入研究这些细节。

    【讨论】:

    • 同意,使用泛型类不应该关心包含类的实现细节。
    • 好吧,这取决于 ;)
    • 你添加到“通用​​”类应该知道如何使用的设计中的接口越多,该类的通用性就越低,使用扩展扩展通用功能会是更好的方法。
    • @nozzleman 谢谢。
    • @Mohit 很高兴我能帮上忙 ;)
    【解决方案2】:

    定义接口:

    public interface IABC
    {
        string Name { get; set; }
        string Address { get; set; }
    }
    

    并在您的通用类定义中指定此接口:

    public class GenericClass<T> where T: IABC
    {
        public GenericClass(T obj)
        {
            DynamicObject = obj;
        }
    
        public IABC DynamicObject { get; set; }    
    }
    

    你所有的 3 个类都实现了这个接口:

    public class A : IABC
    public class B : IABC
    public class C : IABC
    

    之后你可以调用IABC的属性

    A objA = new A("Mohit", "India");
    GenericClass<A> objGenericClass = new GenericClass<A>(objA);
    var adress = objGenericClass.DynamicObject.Address;
    

    【讨论】:

    • 虽然这是有效代码,但我强烈反对这样的实现,因为在这种情况下泛型类完全没用
    • @Maksim 谢谢
    【解决方案3】:

    如果您的通用参数中有共享类型和名称的属性,请使用基类:

    public class Base
    {
        public string Address { get; set; }
    
        public A(string _address)
        {
            Address = _address;
        }        
    }
    
    public class A : Base
    {
        public string Name { get; set; }
    
        public A(string _name, string _address) : base(_address)
        {
            Name = _name;
        }        
    }
    
    public class B : Base
    {
        public string Name { get; set; }
    
        public B(string _name, string _address) : base(_address)
        {
            Name = _name;
        }        
    }
    
    public class C : Base
    {
        public string Name { get; set; }
    
        public C(string _name, string _address) : base(_address)
        {
            Name = _name;
        }        
    }
    

    然后您可以将基类用作泛型类的约束:

    public class GenericClass<T> where T : Base
    {
        public GenericClass(T obj)
        {
            DynamicObject = obj;
        }
    
        public T DynamicObject { get; set; }
    
    
        public void UseClassPro()
        {
            Console.WriteLine("Address " + DynamicObject.Address);//Compiles now
        } 
    }
    

    如果不能使用基类,请使用接口:

    public interface IBase
    {
        string Address { get; set; }
    }
    
    public class A : IBase
    {
        public string Name { get; set; }
        public string Address { get; set; }
    
        public A(string _name, string _address)
        {
            Name = _name;
            Address = _address;
        }        
    }
    
    public class B : IBase
    {
        public string Name { get; set; }
        public string Address { get; set; }
    
        public B(string _name, string _address)
        {
            Name = _name;
            Address = _address;
        }
    }
    
    public class C : IBase
    {
        public string Name { get; set; }
        public string Address { get; set; }
    
        public C(string _name, string _address)
        {
            Name = _name;
            Address = _address;
        }
    }
    
    public class GenericClass<T> where T : IBase
    {
        public GenericClass(T obj)
        {
            DynamicObject = obj;
        }
    
        public T DynamicObject { get; set; }
    
    
        public void UseClassPro()
        {
            Console.WriteLine("Address " + DynamicObject.Address);//Compiles now
        }
    }
    

    【讨论】:

      【解决方案4】:

      如其他答案所示,没有通过接口或基类从没有继承的泛型类中获取属性的“干净”方式。

      如果你不想使用继承,你可以使用反射,虽然这比使用继承类效率低很多。

      // the generic class
      public class GenericClass<T> where T: IABC
      {
          public GenericClass(T obj)
          {
              DynamicObject = obj;
          }
          public IABC DynamicObject { get; set; }    
      
          public T GetPropertyValue<T>(string propertyName)
          {
              var obj = GetType().GetProperty(propertyName).GetValue(this);
              return (T)Convert.ChangeType(obj, typeof(T))
          }
      }
      
      A objA = new A("Mohit", "India");
      GenericClass<A> objGenericClass = new GenericClass<A>(objA);
      var address = objGenericClass.GetPropertyValue<string>("address");
      

      我强调这是继承的替代方法,它不会很快,但它可能适合您的需求。

      【讨论】:

        【解决方案5】:

        添加一个实现类似属性的接口,如下所示:

        public interface IInfo
        {
            public string Name { get; set; }
            public string Address { get; set; }
        }
        
        public class GenericClass<T> where T : IInfo
        {
            public GenericClass(T obj)
            {
                DynamicObject = obj;
            }
        
            public T DynamicObject { get; set; }
        
        
            public void UseClassPro()
            {
                Console.WriteLine("Address " + DynamicObject.Address);
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-09
          • 1970-01-01
          • 1970-01-01
          • 2011-10-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多