如何访问泛型类中泛型成员的属性

时间:2017-01-03 08:04:18

标签: c# generics

我是C#的新手。我正在尝试创建一个Generic类。我有三个类和一个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.
    }

}

5 个答案:

答案 0 :(得分:5)

定义界面:

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;

答案 1 :(得分:5)

其他答案是正确的,但......

我只想指出:虽然其他答案可以促进有效的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在此时有效)
  3. 但是 Nothings对于Generics来说是错误的,它更复杂,而且往往不需要。将上面的类与通用解决方案进行比较:

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

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

    要实际回答您的问题

    您问题的确切答案是:

    您必须定义您的通用参数必须使用

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

    这样,编译器知道T继承或属于IHasAddress类型或您定义的内容。您还可以在此处传递多种类型,这在设计界面时增加了灵活性。

    也许,在您的用例中需要考虑的问题,这些问题从您在问题中提供的信息中并不明显。在这种情况下,请随意添加一些细节,我也很乐意深入了解这些细节。

答案 2 :(得分:1)

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

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
    }
}

答案 3 :(得分:0)

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

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);
    }

}

答案 4 :(得分:0)

没有&#39;清洁&#39;通过接口或基类从没有继承的泛型类获取属性的方法,如其他答案所示。

如果你不想使用继承,你可以使用反射,虽然这远远低于使用继承类的效率。

// 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");

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