开发者

Calling Generic Property In Generic Class From Interface Implemented By Generic Class

I have a generic class that has one type parameter (T). I needed to store a collection of these generic objects that are of different types, so I created a开发者_开发问答n interface that the generic class implements as suggested here. There is a property in the generic class of type T that I need to access when iterating through the generic list that contains the collection of Interface objects. So far the only way I have been able to get the value is to call a method using reflection.

interface ISomeClass {

//?
}

class SomeClass<T> : ISomeClass {

 T ValueINeed { get; set;}
}

class ClassThatHasListOfGenericObjects{

 List<ISomeClass> _l = new List<ISomeClass>();

 public AddToList<T>(T someClass) : where T : ISomeClass {

 _l.Add(someClass);

 }

 public SomeMethod(){

   foreach(ISomeClass i in _l){

   i.ValueINeed; //I don't know how to access the property in the generic class

   }
 }
}


As I see it you have two options. The easy option is to expose the value (as an object) on the interface (and possibly its type as well). Here's how that would look:

interface ISomeClass
{
    object ValueINeed { get; set; }
    // Only needed if you care about static type rather than using ValueINeed.GetType()
    Type TypeOfValue { get; }
}

class SomeClass<T> : ISomeClass
{
    public T ValueINeed { get; set; }
    public Type TypeOfValue { get { return typeof(T); } }

    object ISomeClass.ValueINeed { get { return ValueINeed; } set { ValueINeed = (T)value; } }
}

This has the disadvantage that there's a bit of casting going on and you might need to invoke reflection to do certain things with the value. It has the advantage that it's easy to understand and implement.

The other alternative would be to encode an "existential type" which truly represents a SomeClass<T> for some unknown T (like a SomeClass<?> in Java). This is much more complicated and hard to follow, but avoids any casts:

interface ISomeClassUser<X>
{
    X Use<T>(SomeClass<T> s);
}

interface ISomeClassUser
{
    void Use<T>(SomeClass<T> s);
}

interface ISomeClass
{
    X Apply<X>(ISomeClassUser<X> user);
    void Apply(ISomeClassUser user);
}

class SomeClass<T> : ISomeClass
{
    public T ValueINeed { get; set; }

    public X Apply<X>(ISomeClassUser<X> user) { return user.Use(this); }
    public void Apply(ISomeClassUser user) { user.Use(this); }
}

// Assumes you want to get a string out, use a different generic type as needed
class XmlUser : ISomeClassUser<string>
{
    public string Use<T>(SomeClass<T> s)
    {
        string str = "";
        // do your conditional formatting here, branching on T as needed
        // ...
        return str;
    }
}

class ClassThatHasListOfGenericObjects
{
    List<ISomeClass> _l = new List<ISomeClass>();
    XmlUser user = new XmlUser();

    public string SomeMethod()
    {
        string s = "";
        foreach (ISomeClass i in _l)
        {
            s += i.Apply(user);
        }
        return s;
    }
}


Add ValueINeed to the interface and you'll be able to call it in SomeMethod().


I think you might just need a little refactoring. Looks like you're almost there

interface ISomeClass<T> {
  T ValueINeed { get; set; }
}

class SomeClass<T> : ISomeClass {

 T ValueINeed { get; set;}
}

class ClassThatHasListOfGenericObjects{

 List<ISomeClass> _l = new List<ISomeClass>();

 public AddToList<T>(T someClass) : where T : ISomeClass {

 _l.Add(someClass);

 }

 public SomeMethod(){

   foreach(ISomeClass i in _l){

   i.ValueINeed; //this will work now, since it's in the interface

   }
 }
}


The elements' types you are using is of ISomeClass, so if want to access a member property you need to either cast i to SomeClass or add the property deceleration to the interface

interface ISomeClass {
    T ValueNeeded
    {
        get;
        set;
    }
}

Note that you still need to implement the property in SomeClass.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜