Mike Devenney
Mike Devenney

Reputation: 1845

Handling class specific properties in a generic method

I'm still wrapping my head around generics and have run up against a challenge that I want to work through correctly. If I have a few classes defined like so:

public abstract class DocBase {
    public long ID { get; set; }                                    
    public string Description { get; set; }             
    public long DocumentID { get; set; }                
    public string DocumentDate { get; set; }            
    ...snipped...
}

public class AppDoc : DocBase {
    public string A { get; set; }                                    
    public string B { get; set; }             
    public string C { get; set; }                    
}

public class OtherDoc : DocBase {
    public string D { get; set; }                                    
    public string E { get; set; }             
    public string F { get; set; }                    
}

I have a class that will be used to retrieve these documents

public class Repo<T> where T : DocBase, new() 

This class will contain a method:

public List<T> GetDocs()

In this method I want to be able to access the properties defined in the derived classes (so in AppDoc: A,B,C and in OtherDoc: D,E,F). But if I declare a new object like so:

var doc = new T();

At design time I only have the properties available in the base class (DocBase) and not the dervied classes (AppDoc and OtherDoc). How do I get to properties A, B, C, D, E and F?

EDIT: To elaborate on my "how do I get to..." a bit. I need to populate properties A, B, C, D, E and F within the GetDocs() method from a list of results I get back from a database.

public List<T> GetDocs(){    

var results = someService.GetMyDocuments();
var documents = new List<T>();

    foreach(IRepositoryRow row in results) {
        var newDoc = new T();

        newDoc.A = row.GetProperty("AFromDatabase").ToString();
        newDoc.B = row.GetProperty("BFromDatabase").ToString();

        documents.Add(newDoc);    
    }

    return documents;
}

Upvotes: 0

Views: 316

Answers (2)

Chris
Chris

Reputation: 27599

It depends what are you wanting to do with those properties.

If you are manipulating them (eg populating them or calculating thigns based on them) then an abstract method on DocBase like DoStuff could then be called safely on your T and it could do whatever you want with the properties.

If you want to do different things depending on what the object is then that's not really being very generic and you probably want to rethink things a bit, preferably to having abstract or virtual methods that you can call on the objects.

Some sample code based on what you've put in your question:

public abstract class DocBase {
    ...
    public abstract void LoadProperties(IRepositoryRow row);
    ...
}

public List<T> GetDocs(){    

    var results = someService.GetMyDocuments();
    var documents = new List<T>();

    foreach(IRepositoryRow row in results) {
        var newDoc = new T();
        newDoc.LoadProperties(row);
        documents.Add(newDoc);    
    }
    return documents;
}

Upvotes: 1

Thomas Weller
Thomas Weller

Reputation: 11717

That's generally flawed. Your design would break the laws of polymorphism entirely, because you want access to a a derived class' properties where only base class information is available.

So the question is not How can I ... but What's wrong with my design?.

Edit: OR Mappers (e.g. Entity Framework or NHibernate) can handle such polymorphism scenarios automatically for you. I suggest you take this route.

Upvotes: 2

Related Questions