So I'm using interfaces more these days. But I am coming across a brick wall this time.
Just for context only let me show you the RESTful WCF contract here that I designed to show you how I'm using IPaymentRequest:
[ServiceContract]
public interface IPaymentService
{
[WebInvoke(Method = "POST", UriTemplate = "/PreAuthorization")]
PreAuthorizeResponse SendTransaction(PreAuthorizeRequest request);
[WebInvoke(Method = "POST", UriTemplate = "/Capture")]
CaptureResponse SendTransaction(CaptureRequest captureRequest);
... and so on
}
The implementation of the Service Contract for example has some methods that look like this:
public PreAuthorizeResponse SendTransaction(PreAuthorizeRequest request)
{
.....
Processor.SetSettings(request);
}
(Note/disclaimer on clean code principals. I have better names for stuff like the name SetSettings() but for privacy I've named stuff more simple such as "SetSettings" and "Process" for this Stack post. In reality I have what kind of processor in its class name so just FYI).
Second, let me make you aware that I have a Processor class that is basically kinda like a utility class to do some things such as send the request fields to an outside REST API. And in this class one example of another method I'm setting up is a SetSettings method that I'll set some stuff based on the type of request that comes in. Mostly, I'm going to get the stuff I need from its Transaction property.
public class Processor
{
private void SetSettings(IPaymentRequest request)
{
var someValue = request.Transaction.SomeProperty1;
...
}
}
Now here's what the IPaymentRequest looks like:
public interface IPaymentRequest
{
string Token { get; set; }
int ClientID { get; set; }
}
Now here are a couple examples of my domain models (the Models my Service Contract expects to be sent in from client requests) that implement IPaymentRequest:
public class PreAuthorizeRequest : IPaymentRequest
{
public string Token { get; set; }
public int ClientID { get; set; }
public int Amount { get; set; }
public PreAuthTransaction Transaction { get; set; }
}
public class CaptureRequest : IPaymentRequest
{
public string Token { get; set; }
public int ClientID { get; set; }
public int BankID { get; set; }
public CaptureTransaction Transaction { get; set; }
}
I'm using IPaymentRequest throughout my WCF service (it's the type that's expected to be sent into my payment service's method contracts) and using these interfaces elsewhere in my service to make some good reuse of methods that these requests can flow through such as SendRequest(IPaymentRequest request), and so on.
Here is the dilema/problem I have:
In methods where I want to reuse the logic for any kind of request that comes in, I end up having to check for what type it is incoming to my methods sometimes in my processor class. So I am having to create a bunch of messy if statements in order to determine and cast the incoming ITransaction in order to start using it in my utility mehtods here.
So lets continue more so I can explain more about my First method SetSettings()
Notice that I need values from the transaction object in the request and to be able to work with properties in that TYPE of request.
Now lets take a look at the CaptureTransaction object for example for a CaptureRequest
public class CaptureTransaction : ITransaction
{
public string Reference { get; set; }
public decimal Amount { get; set; }
public string CurrencyCode { get; set; }
public CreditCard CustomerCreditCard { get; set; }
}
So as you can see, for each Request Type I have a related concrete Transaction Type that implements ITransaction and holds info that the transaction needs to send over to an external API.
Note: All requests WILL always have a transaction (ITransaction) so I thought it'd be therefore a good idea to maybe throw ITransaction in my IPaymentRequest so something like this:
public interface IPaymentRequest
{
string Token { get; set; }
int ClientID { get; set; }
ITransaction Transaction {get; set; }
}
And here is ITransaction. Every request that comes into our service will require a currency now and in the future so this field was a good candidate/reason to use an Interface:
public interface ITransaction
{
string CurrencyCode { get; set; }
}
So adding that to my IPaymentRequest now requires me to change the Property Name in my Custom Types to "Transaction", for example:
public class CaptureRequest : IPaymentRequest
{
public string Token { get; set; }
public int ClientID { get; set; }
public int BankID { get; set; }
public ITransaction Transaction { get; set; }
}
I thought ok fine.
But now if I try to work with Transactions in my utility method, since it's an Interface variable, it has no idea what type of Transaction it is. So I end up having to cast it before I can use it:
private void SetSettings(IPaymentRequest request)
{
ITransaction transaction;
if (request is CaptureRequest)
transaction = request.Transaction as CaptureTransaction;
if (request is PreAuthorizeRequest)
transaction = request.Transaction as PreAuthorizeTransaction;
... etc.
var someValue = request.Transaction.Some1;
...carry on and use SomeProperty1elsewhere in this method for whatever reason
}
IMO it just feels strongly like huge code smell. So obviously I am not doing something right or I don't yet know something about Interfaces that I should know...that allows me to use them better here or without so much casting. And just too much casting IMO is bad, performance-wise.
Maybe this is a good case to use Generics instead of interface parameters in methods I want to create for reuse across different types of Concrete Request types (Capture, PreAuth, Void yada yada)?
The whole point here is I want to be able to specify interface params in some methods to make them DRY (don't repeat yourself) / reusable...and then use the concrete type that came in via polymorphism and work with the request instance.
If every request has a transaction, then this is the right way to go:
interface IPaymentRequest
{
string Token { get; set; }
int ClientID { get; set; }
ITransaction Transaction { get; set; }
}
Obviously, to process the custom request, you'll need a custom processor:
class Processor
{
protected virtual void OnSetSettings(IPaymentRequest request)
{
}
private void SetSettings(IPaymentRequest request)
{
// do the common stuff
// ...
// set custom settings
OnSetSettings(request);
}
}
class PreAuthorizeRequestProcessor : Processor
{
protected override void OnSetSettings(IPaymentRequest request)
{
base.OnSetSettings(request);
// set custom settings here
var customRequest = (PreAuthorizeRequest)request;
}
}
As you can see, this requires a little type casting. Yo can avoid casting with generics, but this brings a complexity in types declaration:
interface IPaymentRequest<TTransaction>
where TTransaction : ITransaction
{
string Token { get; set; }
int ClientID { get; set; }
TTransaction Transaction { get; set; }
}
class Processor<TRequest, TTransaction>
where TRequest : IPaymentRequest<TTransaction>
where TTransaction : ITransaction
{
protected virtual void OnSetSettings(TRequest request)
{
}
private void SetSettings(TRequest request)
{
// do the common stuff
// ...
// set custom settings
OnSetSettings(request);
}
}
class PreAuthorizeRequestProcessor : Processor<PreAuthorizeRequest, PreAuthTransaction>
{
protected override void OnSetSettings(PreAuthorizeRequest request)
{
base.OnSetSettings(request);
// set custom settings here
}
}
Explanation to my comment (how to use visitor pattern in this case):
interface IPaymentRequest
{
void Process(IPaymentRequestProcessor processor);
}
class CaptureRequest : IPaymentRequest
{
public void Process(IPaymentRequestProcessor processor)
{
processor.Process(this);
}
}
class PreAuthorizeRequest : IPaymentRequest
{
public void Process(IPaymentRequestProcessor processor)
{
processor.Process(this);
}
}
interface IPaymentRequestProcessor
{
void Process(CaptureRequest request);
void Process(PreAuthorizeRequest request);
}
Where:
private void SetSettings(IPaymentRequest request)
{
IPaymentRequestProcessor processor = new PaymentRequestProcessor();
request.Process(processor);
}
The Visitor pattern is one obvious solution - it allows you to step around the fact that C# can't resolve which subtype of ITransaction you're using at runtime in order to choose a method overload by using a trick called double dispatch. The result of the Visitor pattern is to move the type-specific processing code from a conditional (which can miss cases) to a type definition, which the compiler can enforce the completeness of. The cost, however, is code that bounces around through virtual methods in a way that can be a bit complicated to figure out when you're trying to comprehend it from scratch.
Here's how it works.
ITransaction gains a method Accept(ITransactionVisitor visitor). ITransactionVisitor is an interface which has a Visit method with an override for each ITransaction subclass you want to deal with:
interface ITransactionVisitor {
void Visit(PreAuthTransaction t);
void Visit(VoidTransaction t);
// etc.
}
Then of course you need to implement these methods. Accept is easy, but it does need to be implemented for each implementation of ITransaction. Why? Not just because it's an interface method, but because within that method body the compiler will concretely know the type of the transaction at compile time, so it can choose the right overload in ITransactionVisitor.
public void Accept(ITransactionVisitor visitor) {
visitor.Visit(this);
}
Then all you need to do is implement an appropriate ITransactionVisitor. One of the advantages of this pattern is that you can implement as many as you like with completely different behaviours, and the ITransaction needs no further knowledge or modification (this is why the visitor is specified with an interface or an abstract class).
public class TransactionProcessorVisitor : ITransactionVisitor {
public TransactionProcessorVisitor(/* some suitable context in the constructor so it can do its job perhaps */) { ... }
public void Visit(PreAuthTransaction t) {
// do stuff
}
public void Visit(VoidTransaction t) {
// do other stuff
}
}
So yes, the visitor classes have to know about all the types of transaction, but
It's not in a giant if statement
It's not part of the ITransaction implementations
It's compile-time checked - if you add a new ITransaction type and try to feed it through the processor, the compiler will be able to figure out that there's no Visit method for it and throw an error, rather than waiting until runtime which is the best you can do with the if version.
This is not necessarily the best answer, but it's an answer.
First, let me tell you that your SetSettings method is wrong. var doesn't work like that. From there, your entire thread of reasoning is wrong. Add to it fact you are using some kind of "utility methods" and you have recipe for very bad architecture.
First, I would change those utility methods into some kind of full-featured classes with some interface. I'm sure you could create IProcessor interface and have PreAuthorizeProcessor and CaptureProcessor. From there, you either have IProcessor GetProcessor() method on your IPaymentRequest, which then forces each request into being able to have it's own processor. Or you could use a factory to create specific processor for given request via IProcessor CreateProcessor(IPaymentRequest). Here, you could either hard-code the preocessors or use some kind of subscribe mechanism.
Also, using type checking and casting is not wrong as long as it is properly encapsulated, like inside a factory. And using a visitor pattern is not much different from doing a manual type checking. You still get same kind of advantages and disadvantages from both.
Related
I am trying to limit the use of types by chaining the aggregate IAggregate, the aggregate event IDomainEvent, and Identity together with generics, I have snipped the below code to give context of the issue of what I have got so far.
I have the following interfaces:
public abstract class Identity<T>
{
protected abstract string GetIdentity();
}
public interface IAggregate<T>
{
Identity<T> Identity { get; }
}
public interface IDomainEvent<TIdentity,TIdentity>
where T : Identity<TIdentity>
{
TIdentity Id { get; }
}
I implement with the below:
public class TestUserId : Identity<TestUser>
{
public TestUserId(string name) { Name = name; }
readonly public string Name;
protected override string GetIdentity() => Name.ToLowerInvariant();
}
public class TestUser : IAggregate<TestUser>
{
public TestUser(TestUserId id)
{
Id = id;
var ev = new TestUserCreated()
}
public TestUserId Id { get; }
public Identity<TestUser> Identity => Id;
}
public class TestUserCreated : IDomainEvent<TestUserId, TestUser>
{
public TestUserCreated() { }
public TestUserId Id => throw new NotImplementedException();
}
Then in the command handler, for this event to be used (and for me to be able to obtain the TestUserId which should be member of the domainEvent object).
public interface IDomainEventHandler<TEvent>
{
void Handle(TEvent domainEvent, bool isReplay);
}
That gives me the code:
public class TesterHandler : IDomainEventHandler<TestUser, TestUserCreated>
{
public void Handle(TestUserCreated domainEvent, bool isReplay)
{
// can access the ID (of type TestUserId)
var testUserId = domainEvent.Id;
}
}
So the above TesterHandler is fine exactly how i would want - however the compiler is failing on class TestUserCreated : IDomainEvent<TestUserId, TestUser> with The type TestUserId' cannot be used as type parameter 'TIdentity' in the generic type or method 'IDomainEvent<TIdentity, Type>'. There is no implicit reference conversion from 'TestUserId' to 'Identity<TestUser>'.
What I want is to couple (without OO inheritance) the event to the aggregate, so that it is tied to a specific aggregate type (i.e. specific events are tied to a specific entity, and the entity ID is part of the event type as a field), I want to try and make it impossible to code event handlers for unrelated aggregates.
I am trying to implement but the compiler complains of boxing and implicit casting errors (depending on what i try/guess), in short I am unsure how to code the above.
Given I was unable to create running code as per comments requested (hence the reason for the post) and general complexity, I decided using generics in this way was a bad idea with rationale below.
I currently have code which calls the handler as follows (and this is working fine) passing in the sourceIdentity external to the domainEvent object:
public interface IDomainEventHandler<TIdentity, TEvent>
where TIdentity : IIdentity
where TEvent : IDomainEvent
{
void Handle(TIdentity sourceIdentity, TEvent domainEvent, bool isReplay);
}
I am passing in the aggregate ID external to the IDomainEvent object (and this is desired to keep the events, from an event sourcing perspective, as simple as possible as simple POCO objects without inheritance or involving any framework).
The reason for the question was I just wanted to explore all options with generics (so the domainEvent object could have an interface that would give an ID field) but it started to get complicated quickly, specifically additional template parameters would be required since we are inferring relationships via templates, rather than OO relationships.
Without OO, the relationship would need to be defined somewhere by adding additional types to templates to tie them together interface IDomainEvent<TIdentity,TAggregate,TEvent> and interface IDomainEventHandler<TIdentity, TAggregate, TEvent>, in this case OO inheritance would be preferred and result in way less code.
All this was done to give an interface to obtain the ID, however as if an ID is really needed it can be incorporated in the event as a normal field (without the need for complex OO relationships or templates).
public interface IDomainEvent
{
DateTime OccurredOn { get; set; }
Guid MessageId { get; set; }
}
public class TestUserCreated : IDomainEvent
{
// id can be accessed by whatever needs it by being
// defined explicity within the domain event POCO
// without needing any base class or framework.
public readonly TestUserId Id;
public readonly string Name;
public TestUserCreated(TestUserId id, string name)
{
Id = id;
Name = name;
}
}
I'm deserializing some JSON responses and putting them into one of two primary classes depending on if a single object is returned or if a list of objects is returned. I'm currently using
public class MultiResponse
{
public List<DeserializedResult> Result { get; set; }
}
public class SingleResponse
{
public DeserializedResult Result { get; set; }
}
public class DeserializedResult
{
public string Id { get; set; }
public string AccountName { get; set; }
}
to contain the response(s). However I know it's not the best way, especially since I'm having to use a dynamic return in the calling class to deal with the two types of responses possible. I think an abstract class (or interface?) is a better way to do this, but I don't know how to implement it. Am I on the right track & if so, how do I construct the abstract class and do the inheritance?
Create a design based on multi responses - i.e. holding / returning a list even if when there is only one object. It eliminates the design "hint" that there is a special case somehow. And The resulting code will be more consistent and robust.
The focus should be on the object itself - what you do with it after re-hydration. Not on the trivial happenstance that I have one object or more than one. That distinction is no different that "4 objects or not 4 objects."
Abstracting the container to a single class necessarily makes working with the objects the focus, the emphasis of your design.
edit
Think of it this way. Single or multiple deserialized objects is a consequence of how many objects there were to deserialize. It is an implementation detail not germane to the (deserialized) objects actual use. Encapsulate implementation details, that is, hide them from the client code. Give clients classes and methods that express functionality in "business domain" terms.
end edit
Edit
... I'm having to use a dynamic return in the calling class to deal with the two types of responses possible. I think an abstract class (or interface?) is a better way to do this, but I don't know how to implement it.
Main points:
ClientApi transforms the deserialized object to the desired class.
Two API's!
constructors called by the de-hydrating object
Hide the default constructor to ensure valid object instantiation
GetDeHydratedJsonThingy called by the "using" client.
Deserializer and "using" client are decoupled thanks to the ClientApi class.
De-hydration works with DeserializedResults objects
"Using" client only cares about MultipleResponse objects
"using" client deals with only one return type.
P.S. After I wrote this I realized only one "Response" class is needed, now that ClientApi class encapsulates the object instantiations. Commented out code is original.
P.P.S. My method and parameter names are really lousy. Use names that have meaning in the problem domain. i.e. user's terminology.
.
public class ClientApi {
protected MultiResponse MoreThanOne { get; set; }
// protected SingleResponse OnlyOne { get; set; }
protected ClientApi ( );
public ClientApi (List<DeserializedResult> theList) {
if (theList == null) throw ArgumentNullException("error message here");
// add overloaded constructors to MultiResponse class.
MoreThanOne = new MultiResponse (theList);
// OnlyOne = null;
}
public ClientApi (DeserializedResult onlyOne)
if (onlyOne == null) throw ArgumentNullException("error message here");
MoreThanOne = new MultiResponse(onlyOne);
// OnlyOne = onlyOne;
}
///<summary>
/// Always returns an object. The list may be empty,
/// but never null
///</summary>
public MultiResponse GetDeHydratedJsonThingy() {
MultiResponse HereYaGo = new MultiResponse();
// if (MoreThanOne !=null) HereYaGo.AddRange(MoreThanOne);
// if (OnlyOne != null) HereYaGo.Add(OnlyOne);
HereYaGo.AddRange(MoreThanOne.Result);
return HereYaGo;
}
}
end Edit
You can try the following with a generic base abstract class
public abstract class Response<T> {
public T Result { get; set; }
}
The concrete implementations would inherit from the common base response.
public class Response : Response<object> {
public object Result { get; set; }
}
public class MultiResponse : Response<List<DeserializedResult>> {
public List<DeserializedResult> Result { get; set; }
}
public class SingleResponse : Response<DeserializedResult> {
public DeserializedResult Result { get; set; }
}
I’m writing a custom WebApi Authorization filter.
I need to read the securitySqlConnectionString back from the actionContext variable. To do this, I need to perform a cast (e.g. as I have attempted using TransactionRequestBundle<SearchDefault>), however, the problem is that in TransactionRequestBundle<T>, T will vary, hence the cast below will only work for type TransactionRequestBundle<SearchDefault>. As it turns out, I am not actually concerned with the information stored in T, so I would be happy to disregard the information stored in it. I thought therefore that I might be able to get away with casting to object (as shown here), but this gives me a run-time cast error.
var securitySqlConnectionString =
((TransactionRequestBundle<object>)
actionContext.ActionArguments["transactionRequestBundle"])
.Transaction.SecuritySqlConnectionString;
So can anyone provide me with any guidance on what I need to do to get the line above to work correctly, specifically what do I replace object with?
public class XsycoApiAuthorizationFilter
: ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var securitySqlConnectionString =
((TransactionRequestBundle<object>)
actionContext.ActionArguments["transactionRequestBundle"])
.Transaction.SecuritySqlConnectionString;
if (CacheMachine.GetEnvironments().Count == 0)
{
CacheLoader.Load(securitySqlConnectionString);
}
base.OnActionExecuting(actionContext);
}
}
public class TransactionRequestBundle<T>
{
public Transaction Transaction;
public T Model { get; set; }
public XsycoDebugBundle XsycoDebugBundle { get; set; }
public TransactionRequestBundle()
{
this.Transaction = new Transaction();
this.XsycoDebugBundle = new XsycoDebugBundle();
this.Model = Activator.CreateInstance<T>();
}
}
public class Transaction
{
public string SecuritySqlConnectionString { get; set; }
}
You can take an easier path to solve this problem.
You're trying to cast the object only for reading the Transaction field. What you can do is to create an interface like this:
public interface ITransaction
{
public Transaction Transaction { get; set; }
}
Then implement it in your class
public class TransactionRequestBundle<object> : ITransaction
To implemente it simply convert the Transaction field into a Transaction property, like in the interface:
public Transaction Transaction { get; set; }
And finally, instead of casting to ((TransactionRequestBundle<object>) simply cast it to (ITransaction) which will give you access to that property.
I am struggling to adhere to Liskov substitution principle when creating my class structure. I want to have a Collection of calendar items stored within a Day class. There need to be several different type of CalendarItems e.g:
AppointmentItem
NoteItem
RotaItem
they all share some common functionality which is presnt in the abstract base class CalendarItem:
public abstract class CalendarBaseItem
{
public string Description { get; private set; }
public List<string> Notes { get; private set; }
public TimeSpan StartTime { get; private set; }
public TimeSpan EndTime { get; private set; }
public int ID { get; private set; }
public DateTime date { get; private set; }
code omitted...
}
but then for example RotaItem has some extra functionality:
public class RotaItem : CalendarBaseItem
{
public string RotaName { get; private set; }
private bool spansTwoDays;
public bool spanTwoDays()
{
return this.spansTwoDays;
}
}
the other classes also add there own logic etc.
I have a collection of CalendarBaseItem for my day class:
List<CalendarBaseItem> calendarItems;
but on reviewing this I can see that I am breaking LSP principles as I have to check and cast each concrete type to get at the functionality that I desire for each subclass.
I would be grateful if someone could advise how to avoid this problem. Should I use a composition approach and add a CalendarItem class to each of the final classes e.g
public class RotaItem
{
private CalendarBaseItem baseItem;
public string RotaName { get; private set; }
private bool spansTwoDays;
public RotaItem(baseArgs,rotaArgs)
{
baseItem = new CalendarBaseItem(baseArgs);
}
public bool spanTwoDays()
{
return this.spansTwoDays;
}
}
The only problem here is that I will then need a seperate collection for each Concrete CalendarItem in my Day class?
I think what you're encountering is not so much a Liskov Substitution Principle violation as you are encountering a polymorphism limitation in most languages.
With something like List<CalendarBaseItem> the compiler is inferring that you're only dealing with CalendarBaseItem which obviously can't be true if CalendarBaseItem is abstract--but that's what a strongly-typed language does: It's only been told about CalendarBaseItem so that's what it limits usage to.
There are patterns that allow you to deal with this sort of limitation. The most popular is the double-dispatch pattern: a specialization of multiple dispatch that dispatches method calls to the run-time type. This can be accomplished by providing an override, that when dispatched, dispatches the intended method. (i.e. "double dispatch"). It's hard to associate exactly to your circumstances because of the lack of detail. But, if you wanted to do some processing based on some sort of other type for example:
public abstract class CalendarBaseItem
{
abstract void Process(SomeData somedata);
//...
}
public class RotaItem : CalendarBaseItem
{
public override void Process(SomeData somedata)
{
// now we know we're dealing with a `RotaItem` instance,
// and the specialized ProcessItem can be called
someData.ProcessItem(this);
}
//...
}
public class SomeData
{
public void ProcessItem(RotaItem item)
{
//...
}
public void ProcessItem(NoteItem item)
{
//...
}
}
which would replace something like:
var someData = new SomeData();
foreach(var item in calendarItems)
someData.ProcessItem(item);
Now, that's the "classical" way of doing in in C#--which spans all versions of C#. With C# 4 the dynamic keyword was introduced to allow run-time type evaluation. So, you could do what you want without having to write the double-dispatch yourself simply by casting your item to dynamic. Which forces the method evaluation to occur at run-time and thus will chose the specialized override:
var someData = new SomeData();
foreach(var item in calendarItems)
someData.ProcessItem((dynamic)item);
This introduces potential run-time exceptions that you'd likely want to catch and deal with--which is why some people don't like this so much. It's also currently very slow in comparison, so it's not recommended in tight loops that are performance sensitive.
I would like to be able to pass a known type to a general function but I'm getting compile errors because I can't cast the type at design time.
Consider my OnCreate function:
EXAMPLE 1:
private void OnCreate<T>(T object)
{
object.CurrentDate = DateTime.Now;
object.SpecialProperty = "Hello";
}
EXAMPLE 2:
private void OnCreate<T>(T object)
{
object.BirthDate = DateTime.Now;
object.BirthdayMessage = "Happy Birthday";
}
I want to call OnCreate and pass to it an object. That object happens to be a model object in an MVC application. I can't predict what model object is being passed to OnCreate yet I want to access the unique properties of the model that is passed. As my examples show above, one model has a CurrentDate and a SpecialProperty property; another has a BirthDate and a BirthdayMessage property. I don't want to create a special function for each because I have many different models. Also, this OnCreate function is going to get inherited from a base class. The idea here is to provide a "hook" into the controller's Create method so that someone can alter the model properties before they are persisted to the database. In other words, the controller's Create method would pass the model to my OnCreate function, then some work would be done on the model before it's passed back.
As you would expect, each model has different properties. Due to this requirement, I realize that I won't be able to early-bind and get intellisense with the OnCreate function--but my problem is that the compiler won't let me refer to properties of the object until it knows the object type. I can't cast it at design-time because I don't know the type until run-time.
EDIT
I think my question wasn't so clear, judging by the answers (for which I'm grateful--they're just not what I'm looking for). Perhaps it's better to show how I want to call OnCreate():
OnCreate(model);
Now, when OnCreate receives object "model", it needs to be able to set properties on that model. I suppose I could use reflection on the model and do something like this (this is pseudocode only--still learning about reflection):
if typeof(model) is CustomerModel then
(CustomerModel(model)).BirthDate = "1/1/1960";
(CustomerModel(model)).BirthdayMessage = "Happy Birthday";
elseif typeof(model) is AnotherModel then
(AnotherModel(model)).CurrentDate = DateTime.Now;
(AnotherModel(model)).SpecialProperty = "Hello";
etc...
But I am trying to avoid having a bunch of if/then statements. I prefer if the call could be "routed" to a function that's specific for the type being passed. That way, the call to OnCreate would send the object to an overload(?) so that no reflection logic is needed...
SECOND EDIT
Upon further reflection (no pun intended), I don't think having a bunch of if/else statements in the OnCreate function is the best approach here. I came up with another idea that might work best and accommodates my expressed wish to "avoid having a bunch of if/then statements" (specified in my first Edit): The idea is to have my models implement IOnCreate, which would provide the .OnCreate() method. Thus, my "generic" model objects that implement IOnCreate could be used this way:
model.OnCreate();
Then the OnCreate function would know what properties are on the model:
public void OnCreate()
{
this.BirthdayMessage = "Happy Birthday";
etc...
}
I just see two issues here:
1 - In the controller I would need to test that the model implements IOnCreate--if it doesn't, I wouldn't try to call OnCreate().
2 - I need to be sure that adding a public function such as OnCreate() will not interfere with how EF6 generates database tables in a code-first project.
My question now is whether this approach be best... or whether there is any other idea to consider...
Since T is any type, compiler can't expect it having CurrentDate or SpecialProperty;
you could try solving the problem like that:
public interface IMyInterface {
DateTime CurrentDate {get; set}
String SpecialProperty {get; set}
}
public class MyClassA: IMyInterface {...}
public class MyClassB: IMyInterface {...}
public class MyClassC: IMyInterface {...}
...
private void OnCreate<T>(T value)
where T: IMyInterface // <- T should implement IMyInterface
{
value.CurrentDate = DateTime.Now;
value.SpecialProperty = "Hello";
}
By your example it seems unlikely the Generics are the the solution for you problem (your app), it would seems that a use of an abstract layer (Interface or Abstract Class) is more appropriate.
When using "bare bone" generics any Type can be passed to your method, now since any type in .Net is of type Object you can execute any object related functionality on those generics parameters. To extend this ability of the generics to implements the most basic type in the inheritance hierarchy we have Generics Constraints, those allow you to limit the range of types that can be passed as a generic argument. In your case you'd want to use Type Constraints, which limit the range of types to only those which implement the type specified.
For example, we have type A, and the A has types B and C as derived classes, we want method M to accept only type how implements A:
class Program
{
static void Main(string[] args)
{
M(new A()); // will work
M(new B()); // will work
M(new C()); // will work
M(new D()); // wont work
}
public static string M<T>(T arg)
where T : A
{
return arg.Data;
}
}
public class A { public string Data { get; set; } }
public class B : A { }
public class C : B { }
public class D { }
Edit
According to your last edit it would seems that you have two options to solve this problem.
Implementing an abstraction layer (an Interface): You may want to add an interface and implement it by your models.
public static void OnCreate(IBirthable arg)
{
arg.BirthDate = ...;
}
Interface:
public interface IBirthable
{
DateTime BirthDate { get; set; }
string BirthdayMessage { get; set; }
}
Models:
public class CustomerModel : IBirthable
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}
public class AnotherModel : IBirthable
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}
Using reflection: If you choose not to use an interface, perhaps is has no logical connection with your models you may want use reflection.
public static void OnCreate<T>(T arg)
{
var type = arg.GetType();
var birthDateProperty = type.GetProperty("BirthDate");
if (birthDateProperty == null)
throw new ArgumentException("Argument not is implementing the model");
birthDateProperty.SetValue(arg, DateTime.Now);
//And so on...
}
Models:
public class CustomerModel
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}
public class AnotherModel
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}