I have the following class;
public class PricingRuleNumberRange
{
public decimal? FromValue { get; private set; }
public decimal? ToValue { get; private set; }
protected PricingRuleNumberRange() {}
public PricingRuleNumberRange(decimal? fromValue, decimal? toValue)
{
FromValue = fromValue;
ToValue = toValue;
}
...
}
And a model which uses said class;
public class PricingRule
{
public PricingRuleNumberRange LVR { get; private set; }
protected PricingRule() { }
public PricingRule(...)
{
...
}
public void UpdateDetails(PricingRuleNumberRange lvr)
{
LVR = lvr;
}
}
I can add a new PricingRuleNumberRange property to PricingRule and call Add-Migration, it will detect and scaffold the change without issue. However, I now need to add another PricingRuleNumberRange property that is only an int, not a decimal. I thought that converting the PricingRuleNumberRange to a generic class would be acceptable but Add-Migration now drops the LVR property/columns.
This is the new code;
public class PricingRuleNumberRange<T> where T : struct, IComparable<T>
{
public T? FromValue { get; private set; }
public T? ToValue { get; private set; }
protected PricingRuleNumberRange() {}
public PricingRuleNumberRange(T? fromValue, T? toValue)
{
FromValue = fromValue;
ToValue = toValue;
}
...
}
public class PricingRule
{
public PricingRuleNumberRange<decimal> LVR { get; private set; }
public PricingRuleNumberRange<int> NewCol { get; private set; }
protected PricingRule() { }
public PricingRule(...)
{
...
}
public void UpdateDetails(PricingRuleNumberRange<decimal> lvr)
{
LVR = lvr;
}
}
Since I am specifying int/decimal in the property declaration, I thought it would pick it up still, but obviously not. I suspect I might need to do something in the DbContext.OnModelCreating() method or maybe add some attributes to some properties to get it to work?
Related
I'm trying to do something like that:
internal class ConcreteLinkedItem : GenericLinkedItem<ConcreteLinkedItem>
{ //Specific methods which use GenericLinkedItem
}
internal class GenericLinkedItem<TItem>
where TItem : GenericLinkedItem<TItem>
{
public TItem? Next { get; private set; }
public TItem? Previous { get; private set; }
public void AttachNext(TItem item)
{
Next = item;
//Error CS0266 Cannot implicitly convert type 'GenericLinkedItem<TItem>' to 'TItem'...
item.Previous = this;
}
}
The only solutions I have in mind are:
Explicit cast (no compile time type check)
item.Previous = (TItem)this;
Abstract method to retrieve this (boilerplate)
public void AttachPrevious(TItem item)
{
Previous = item;
item.Next = GetThis();
}
protected abstract TItem GetThis();
Use composition instead of inheritance aka System.Collections.Generic.LinkedList (even more boilerplate).
Any beautiful ideas?
PS: For now I go with "protected abstract TItem This { get; }". Which still is not what I want as you can mix different item (node) types, but is at least type safe:
internal class ConcreteLinkedItem : GenericLinkedItem<ConcreteLinkedItem>
{ //Specific methods which use GenericLinkedItem
protected override ConcreteLinkedItem This => this;
}
internal abstract class GenericLinkedItem<TItem>
where TItem : GenericLinkedItem<TItem>
{
public TItem? Next { get; private set; }
public TItem? Previous { get; private set; }
public void AttachPrevious(TItem item)
{
Previous = item;
item.Next = This;
}
protected abstract TItem This { get; }
}
use an interface:
internal class ConcreteLinkedItem : IGenericLinkedItem<ConcreteLinkedItem>
{
public ConcreteLinkedItem? Next { get; private set; }
public ConcreteLinkedItem? Previous { get; private set; }
public void AttachNext(ConcreteLinkedItem item)
{
Next = item;
item.Previous = this;
}
}
internal interface IGenericLinkedItem<TItem> where TItem : IGenericLinkedItem<TItem>
{
TItem? Next { get; }
TItem? Previous { get; }
void AttachNext(TItem item);
}
or if you must have a generic class then you'll need a cast:
internal class ConcreteLinkedItem : BaseLinkedItem<ConcreteLinkedItem>
{
//Specific methods which use GenericLinkedItem
}
internal class BaseLinkedItem<TItem> : IGenericLinkedItem<TItem> where TItem : BaseLinkedItem<TItem>
{
public TItem? Next { get; private set; }
public TItem? Previous { get; private set; }
public void AttachNext(TItem item)
{
Next = item;
item.Previous = (TItem)this;
}
}
internal interface IGenericLinkedItem<TItem> where TItem : IGenericLinkedItem<TItem>
{
TItem? Next { get; }
TItem? Previous { get; }
void AttachNext(TItem item);
}
I want to transform two properties of base classes using ConvertUsing, but it is not being called
Base classes
public abstract class BaseDadoMestreViewModel
{
public DateTime UltimaAtualizacao { get; set; }
public bool Excluido { get; set; }
public bool Ativo { get; set; }
}
public abstract class BaseDadoMestre<TEntity> : EntityCrud<TEntity>
where TEntity : class
{
public DateTime UltimaAtualizacao { get; set; }
public string MarcadoEliminacao { get; set; }
public bool Desabilitado { get; set; }
}
Classes
public class CalendarioViewModel: BaseDadoMestreViewModel
{
public DateTime Data { get; set; }
}
public class CalendarioDTO: BaseDadoMestre<CalendarioDTO>
{
public DateTime Data { get; set; }
}
ITypeConverter
public class BaseConverter<TEntity> :
ITypeConverter<BaseDadoMestre<TEntity>, BaseDadoMestreViewModel>,
ITypeConverter<BaseDadoMestreViewModel, BaseDadoMestre<TEntity>>
where TEntity : BaseDadoMestre<TEntity>
{
public BaseDadoMestreViewModel Convert(BaseDadoMestre<TEntity> source, BaseDadoMestreViewModel destination, ResolutionContext context)
{
destination.Excluido = (source.MarcadoEliminacao== "X");
destination.Ativo = !source.Desabilitado;
return destination;
}
public BaseDadoMestre<TEntity> Convert(BaseDadoMestreViewModel source, BaseDadoMestre<TEntity> destination, ResolutionContext context)
{
destination.MarcadoEliminacao = (source.Excluido ? null : "X");
destination.Desabilitado = !source.Ativo;
return destination;
}
}
And finally my map:
CreateMap(typeof(BaseDadoMestre<>), typeof(BaseDadoMestreViewModel)).ConvertUsing(typeof(BaseConverter<>));
CreateMap(typeof(BaseDadoMestreViewModel), typeof(BaseDadoMestre<>)).ConvertUsing(typeof(BaseConverter<>));
CreateMap<CalendarioDTO, CalendarioViewModel>()
When I run the mapping command ConvertUsing is not called.
mapper.Map<CalendarioViewModel>(new CalendarioDTO() { MarcadoEliminacao = "X", Desabilitado = true });
As from Automapper docs you need to either specify the inheritance when creating the mapping for base classes either from derived.
Check this one:
http://docs.automapper.org/en/stable/Mapping-inheritance.html
Original Question
So I have this 3 objects...
public class obj1
{
public int Id { get; set; }
public string Name { get; set; }
}
public class obj2
{
public int AccNum { get; set; }
public string Name { get; set; }
}
public class obj3
{
public string Email { get; set; }
public string Phone { get; set; }
}
... and one method that is supposed to receive one of them, after evaluating the object type the program should decide which function to call.
I've tried with generics but it doesn't work as I expected. So far this is what I've got...
public class NotificationHelper: INotificationHelper
{
public bool SendNotification<TNotInfo>(TNotInfo obj) where TNotInfo : class
{
if (contract.GetType() == typeof (obj1))
{
var sender = new SendSMS();
return sender.Send(obj);
}
if (contract.GetType() == typeof(obj2))
{
var sender = new SendPush();
return sender.Send(obj);
}
else
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
}
but I get the error "Cannot convert from TNotInfo to Models.obj1". Is there any way to overcome this issue? Or I have to change my logic?
Appreciate any help, thanks in advance.
*Edit
using System;
namespace EmailNotifications
{
public interface IEmailNotification
{
void SendEmailNotification();
}
public class EmailNotificationA : IEmailNotification
{
public void SendEmailNotification(Contract1 a)
{
Console.WriteLine($"Sending EmailNotificationA ({a})");
}
}
public class EmailNotificationB : IEmailNotification
{
public void SendEmailNotification(Contract2 b)
{
Console.WriteLine($"Sending EmailNotificationB ({b})");
}
}
public class EmailNotificationC : IEmailNotification
{
public void SendEmailNotification(Contrac3 c)
{
Console.WriteLine($"Sending EmailNotificationC ({c})");
}
}
public class EmailNotificationService
{
private readonly IEmailNotification _emailNotification;
public EmailNotificationService(IEmailNotification emailNotification)
{
this._emailNotification = emailNotification;
}
public void ServiceHelper()
{
_emailNotification.SendEmailNotification();
}
}
}
Above solution is what I was trying to achieve, applying strategy design pattern. But I couldn't manage to make my interface method receive different objects, this is required because each notification has is own implementation. As visible at the none working example above, I have 3 different implementation of the same method all of them receiving different objects. Any idea of how to make this logic work?
This is the kind of thing that interfaces were designed to do. First, define a common interface:
public interface INotifier
{
bool Notify();
}
Second, implement it in your objX classes:
public class obj1 : INotifier
{
public int Id { get; set; }
public string Name { get; set; }
public bool Notify()
{
var sender = new SendSMS();
return sender.Send(this);
}
}
public class obj2 : INotifier
{
public int AccNum { get; set; }
public string Name { get; set; }
public bool Notify()
{
var sender = new SendPush();
return sender.Send(this);
}
}
public class obj3 : INotifier
{
public string Email { get; set; }
public string Phone { get; set; }
public bool Notify()
{
var sender = new SendEmail();
return sender.Send(this);
}
}
And finally, change your notification method to accept the interface type as the parameter:
public class NotificationHelper : INotificationHelper
{
public bool SendNotification(INotifier obj)
{
return obj.Notify();
}
}
Edit (2019):
I'm revisiting this answer as it seems to be getting a fair amount of visibility. OP has probably long since moved on, but for others that may stumble upon this answer, here's another solution.
I still believe that interfaces are the way to go. However, the interface suggested above is extremely generic and ultimately not terribly useful. It also runs into some DRY violations because, as Fabio said in a comment, if two objX classes implement notifications in the same way, this approach forces you to duplicate the code between them.
Instead of one global interface, instead have interfaces for each specific notification task, i.e. ISMSNotification, IPushNotification, IEmailNotification. You can then use the mixin pattern to give each interface instance a default implementation of the send method:
interface ISmsNotifier
{
int SmsId { get; }
string SmsName { get; }
}
static class ISmsNotifierExtensions
{
public static bool NotifySms(this ISmsNotifier obj)
{
var sender = new SendSMS();
return sender.Send(obj);
}
}
// ---------------------------------------------
interface IPushNotifier
{
int PushAccNum { get; }
string PushName { get; }
}
static class IPushNotifierExtensions
{
public static bool NotifyPush(this IPushNotifier obj)
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
// ---------------------------------------------
interface IEmailNotifier
{
string EmailAddress { get; }
string EmailPhone { get; }
}
static class IEmailNotifierExtensions
{
public static bool NotifyEmail(this IEmailNotifier obj)
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
You can then implement it in the objX classes like so:
public class obj1 : INotifier, ISmsNotifier
{
public int SmsId { get; set; }
public string SmsName { get; set; }
public bool Notify() => this.NotifySms();
}
public class obj2 : INotifier, IPushNotifier
{
public int PushAccNum { get; set; }
public string PushName { get; set; }
public bool Notify() => this.NotifyPush();
}
public class obj3 : INotifier, IEmailNotifier
{
public string EmailAddress { get; set; }
public string EmailPhone { get; set; }
public bool Notify() => this.NotifyEmail();
}
Notice that using this approach it's easy to not only support objects which use identical notification systems, you can also support objects with multiple notification systems:
public class obj4 : INotifier, IEmailNotifier, IPushNotifier
{
public int PushAccNum { get; set; }
public string PushName { get; set; }
public string EmailAddress { get; set; }
public string EmailPhone { get; set; }
public bool Notify() => this.NotifyEmail() && this.NotifyPush();
}
You might notice that this approach makes NotificationHelper obsolete since it's no longer necessary to pass the objects through a processing step to determine which notification system to process the object through. That is true, and maybe rightfully so, since the objects should be fully capable of deciding that for themselves (depending on your mentality approaching this problem). However, NotificationHelper may still have its uses, such as if you wanted to preprocess the information that's getting sent to the notification services, or if you wanted a common point of entry to help with mocking and testing.
C# 8 Note:
A proposed feature of C# 8 is the ability to give interfaces a default implementation of methods within the interface definition itself. When (if) that happens, you don't need to use the mixin pattern anymore and can directly define the default method implementations in the interfaces. The feature hasn't yet been finalized, but it might look something like this:
interface ISmsNotifier
{
int SmsId { get; }
string SmsName { get; }
public bool NotifySms()
{
var sender = new SendSMS();
return sender.Send(this);
}
}
// ---------------------------------------------
interface IPushNotifier
{
int PushAccNum { get; }
string PushName { get; }
public bool NotifyPush()
{
var sender = new SendEmail();
return sender.Send(this);
}
}
// ---------------------------------------------
interface IEmailNotifier
{
string EmailAddress { get; }
string EmailPhone { get; }
public bool NotifyEmail()
{
var sender = new SendEmail();
return sender.Send(this);
}
}
Another approach will be overload methods.
Because you have different logic based on the given type. And types have nothing in common (interface/abstract class).
public class NotificationHelper
{
public bool SendNotification(obj1 obj)
{
var sender = new SendSMS();
return sender.Send(obj);
}
public bool SendNotification(obj2 obj)
{
var sender = new SendPush();
return sender.Send(obj);
}
public bool SendNotification(obj3 obj)
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
Then using will be clear enough
var someObject = GetObjectFromSomeWhere();
var isSuccessful = SendNotification(someObject);
I would suggest creating a parent class from which these 3 inherit
public class ParentType { }
public class Obj1 : ParentType { ... }
The method would then just request the parent type, such as:
public bool SendNotification(ParentType obj) { ... }
I have a generic class
public class MetadataDifference<T>
{
public T NewMetadata { get; private set; }
public T OldMetadata { get; private set; }
// Other useful properties
public MetadataDifference(T newMetadata, T oldMetadata)
{
NewMetadata = newMetadata;
OldMetadata = oldMetadata;
}
}
I have wrapper class which has a list of MetadataDifference<> as a property.
This doesn't work:
The type or namespace name 'T' could not be found
Code:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<T>> MetadataChanges { get; set; }
// other fields
}
How can I initialize a list of a generic object? Is it possible?
Either enclosing type must be opened generic:
public class DifferencesResult<T>
{
public IEnumerable<MetadataDifference<T>> MetadataChanges { get; set; }
// other fields
}
or you should use methods instead of property:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<T>> GetMetadataChanges<T>();
private void SetMetadataChanges<T>(IEnumerable<MetadataDifference<T>> value)
// other fields
}
In C#, you can't hold generic property in non-generic class.
It depends on what result you want to achieve.
Here you should use a closed type, for example:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<string>> MetadataChanges { get; set; }
// other fields
}
As you cannot have a generic property in a non-generic class.
You could either close it:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<{sometype}>> MetadataChanges { get; set; }
// other fields
}
or use dynamic:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<dynamic>> MetadataChanges { get; set; }
// other fields
}
Define an interface that doesn't have any generic types which MetadataDifference implements to provide untyped access to the underlying object:
public interface IMetadataDifference
{
object NewMetadata { get; }
object OldMetadata { get; }
}
public interface IMetadataDifference<out T> : IMetadataDifference
{
new T NewMetadata { get; }
new T OldMetadata { get; }
}
public class MetadataDifference<T> : IMetadataDifference<T>
{
object IMetadataDifference.NewMetadata { get { return NewMetadata; } }
object IMetadataDifference.OldMetadata { get { return OldMetadata; } }
public T NewMetadata { get; private set; }
public T OldMetadata { get; private set; }
// Other useful properties
public MetadataDifference(T newMetadata, T oldMetadata)
{
NewMetadata = newMetadata;
OldMetadata = oldMetadata;
}
}
public class DifferencesResult
{
public IEnumerable<IMetadataDifference> MetadataChanges { get; set; }
// other fields
}
I have a business model which consists of a parent/child relationship (Identifier/IdentifierValue) and also some snapshot classes which look the same (IdentifierSnapshot/IdentifierValueSnapshot).
I am trying to create an extension method which will work on an enumeration of either Identifier or IdentifierSnapshot, but I just can't work out what to put in the extension method where I have inserted the XXX placeholder.
//Interfaces
public interface IIdentifier<TIdentifierValue>
where TIdentifierValue : IIdentifierValue
{
string Code { get; }
IEnumerable<TIdentifierValue> GetValues();
}
public interface IIdentifierValue
{
string Code { get; }
string Value { get; }
}
//Main classes
public class Identifier : IIdentifier<IdentifierValue>
{
public string Code { get; set; }
public IEnumerable<IdentifierValue> GetValues();
}
public class IdentifierValue : IIdentifierValue
{
public string Code { get; set; }
public string Value { get; set; }
}
//Snapshots
public class IdentifierSnapshot : IIdentifier<IdentifierValueSnapshot>
{
public string Code { get; set; }
public IEnumerable<IdentifierValueSnapshot> GetValues();
}
public class IdentifierValueSnapshot : IIdentifierValue
{
public string Code { get; set; }
public string Value { get; set; }
}
public static IdentifierExtensions
{
public static IEnumerable<XXX> ByCode<XXX>(this IEnumerable<XXX> instance, string code)
{
return instance.Where(x => string.Compare(code, x.Code, true) == 0);
}
}
I think this would do it:
public static IEnumerable<T> ByCode<T,Z>(this IEnumerable<T> instance, string code)
where T:IIdentifier<Z>
where Z:IIdentifierValue