First of all, I appreciate the fact that you want to keep your code DRY as many developers are not concerned with this. Also, I like the idea of having the generic Data
type. This makes your code flexible so that in the future new, more derived types of Data
can be created without affected significant portions of unrelated code. That being said, there are some things I would consider.
Style Notes:
- Use consistent syntax conventions
On some lines, you have an opening curly on a new line, on others, it is on the same line as the function block / signature. Either way is fine, just make sure you're consistent.
- For generic types, give them more descriptive names than T to improve readability
Presumably, your T is a Data
type (more on this later), so name your generic type parameter: TData
, instead of T
. This gives a more clear understanding of what is expected.
Programming Notes:
As far as your use of Generics goes, I would use something more like this (and I'll explain why):
public class Request<TData> where TData : Data {
public Request() {
this.RequestDetail = new Details<TData>();
} // end default constructor
public string ApiKey { get; set; }
public Details<TData> RequestDetail { get; set; }
} // end class Request{TData}
public class Details<TData> where TData : Data {
public Details() {
this.DetailData = new MoreDetails<TData>();
} // end default constructor
public string Action { get; set; }
public string SecondAction { get; set; }
public MoreDetails<TData> DetailData { get; set; }
} // end class Details{TData}
public class MoreDetails<TData> where TData : Data {
public TData RequestData { get; set; }
} // end class MoreDetails{TData}
public class Data {
public string Query { get; set; }
} // end base class Data
public class SpecialData : Data {
public string AdditionalQuery1 { get; set; }
public string AdditionalQuery2 { get; set; }
} // end derived class SpecialData
Then, in your implementation:
Request<Data> newRequest = new Request<Data>();
newRequest.ApiKey = "12345";
newRequest.RequestDetail.Action = "Search";
newRequest.RequestDetail.DetailData.RequestData = new Data(); //You could also use SpecialData
What I did:
1. Use Generic Type Constraints
Using Generic type constraints is a great way to both enhance the readability and maintainability of your code because you'll have some basic compile-time checking. It also tells future developers what your expectations are.
See here for more on this subject: http://msdn.microsoft.com/en-us/library/d5x73970.aspx
2. Give more specific names to properties and fields
Your naming of properties being the same as the class names is confusing. I renamed some of the properties to make the code easier to understand. In addition to this, I would think of more descriptive names for your classes than Detail
and MoreDetail
as these don't really help understand the code or how it should be used. Without knowing more about what your final aim is, I can't really provide more useful names, but you should consider being more explicit.
3. Instantiate defaults for complex types in constructors
You are passing generic type arguments for your initial request, which doesn't seem like what you want. All of your generics ultimately are interested in what TData
will be, not the property chain all the way down. The generic type argument only specifies the type of, not the actual value of the property (which is why I have an additional assignment in my implementation code) that actually creates a new instance of the Data
class.
By instantiating each property within the constructor, the object creation is simpler in your implementation. Additionally, your implementation should not have to be concerned with the finer details of how the class and it's property chains are initialized. The fact that your implementation code has to go so many levels deep in your properties may be a code smell. Also, I am unclear on the usefulness of the MoreDetail
class.
4. Simplify object creation
The object initializer syntax you're using is helpful sometimes, but when you are creating a complex object, it's best to KISS to improve the readability of the code (remember, this isn't JavaScript ;) ).
Let me know if I need to add any clarification on these points.
SearchRequest
andUpdateRequest
both derived fromRequest
, while makingSecondAction virtual get
orprotected set
. Any problem with such solution? \$\endgroup\$