3

I have those classes:

public class FilterBackOfficeDiscountFilterType
{
    public FilterBackOfficeDiscountFilterType();
    public FilterBackOfficeDiscountFilterType(string filterValue = null, string filterType = null);

    [JsonProperty(PropertyName = "filterType")]
    public string FilterType { get; set; }
    [JsonProperty(PropertyName = "filterValue")]
    public string FilterValue { get; set; }
}

And my:

 public abstract class Filter<T>
    where T : struct
{
    public T Type { get; set; }
    public string Value { get; set; }
}

And:

 public class DiscountFilter : Filter<DiscountFilterType>
{


}

I want to cast DiscountFilter to FilterBackOfficeDiscountFilterType in explicit or implicit way.

So I add operator method:

 public class DiscountFilter : Filter<DiscountFilterType>
{
    public static implicit operator FilterBackOfficeDiscountFilterType(DiscountFilter filter)
        => new FilterBackOfficeDiscountFilterType(filterType: filter.Type.ToString(), filterValue: filter.Value);
}

But it do not compile because:

Cannot implicitly convert type 'Filter<DiscountFilterType>' to 'FilterBackOfficeDiscountFilterType'

How I can do it?

DiscountFilterType is a enum.

And FilterCreator.Create is:

public class DiscountFilterCreator : FilterCreator<DiscountFilterType>
{
    public override Filter<DiscountFilterType> Create(DiscountFilterType type, string value)
        => new DiscountFilter {Type = type, Value = string.IsNullOrWhiteSpace(value) ? null : value};
}

It derives from:

public abstract class FilterCreator<T>
    where T : struct
{
    public abstract Filter<T> Create(T type, string value);
}

And last Filter is:

public abstract class Filter<T>
    where T : struct
{
    public T Type { get; set; }
    public string Value { get; set; }
}

Edit to reproduce the issue you have to do this

DiscountFilter filter = new DiscountFilterCreator().Create(DiscountFilterType.normal, "wow"); 

EDIT

DiscountFilter x = this.FilterCreator.Create(DiscountFilterType.BrandId, brandId);
        FilterBackOfficeDiscountFilterType y = x;

Edit It works:

    DiscountFilter x = (DiscountFilter)this.FilterCreator.Create(DiscountFilterType.BrandId, brandId);
        FilterBackOfficeDiscountFilterType y = x;

but I want to do it this way:

    FilterBackOfficeDiscountFilterType  x = this.FilterCreator.Create(DiscountFilterType.BrandId, brandId);

So I need this implicit conversion too:

   public class DiscountFilter : Filter<DiscountFilterType>
{
    public static implicit operator DiscountFilter(Filter<DiscountFilterType> filter)
        => new DiscountFilter {Value = filter.Value};
    public static implicit operator FilterBackOfficeDiscountFilterType(DiscountFilter filter)
        => new FilterBackOfficeDiscountFilterType(filterType: filter.Type.ToString(), filterValue: filter.Value);
}

But the implicit casting from derivered class to base is not allowed!

DiscountFilter.implicit operator DiscountFilter(Filter<DiscountFilterType>): user-defined conversions to or from a base class are not allowed   
Nerf
  • 938
  • 1
  • 13
  • 30

2 Answers2

3

(Implicit) user-defined conversions from base class to derived class are a bad idea and as such not supported by the language as already explained here: User-defined conversion operator from base class

As a solution to your problem, I'd propose to adjust your base types as follows:

public abstract class FilterCreator<TFilter, TFilterType>
    where TFilter : Filter<TFilterType>
    where TFilterType : struct
{
    public abstract TFilter Create(TFilterType type, string value);
}

public abstract class Filter<T>
    where T : struct
{
    public T Type { get; set; }
    public string Value { get; set; }
}

Then you can just implement the DiscountFilterCreator as

public class DiscountFilterCreator : FilterCreator<DiscountFilter, DiscountFilterType>
{
    public override DiscountFilter Create(DiscountFilterType type, string value)
        => new DiscountFilter { Type = type, Value = string.IsNullOrWhiteSpace(value) ? null : value };
}

Using this, you will no longer need casts since the returned type is the expected type.

Not sure this is exactly what you want. The code seems very abstract by C#'s standards, it's probable that there is a better design for your needs.

EDIT: Just as a side note, this implementation renders the FilterCreator very close to useless. The usefulness of Filter<T> seems rather questionable as well - do you ever declare a variable or generic contraint of type Filter<T>?

Community
  • 1
  • 1
Zdeněk Jelínek
  • 2,611
  • 1
  • 17
  • 23
1

To reproduce your issue you are trying to cast a base generic class to a derived class.

something like this

DiscountFilter filter = new DiscountFilterCreator().Create(DiscountFilterType.normal, "wow"); 

to resolve your issue you have to cast to the derived class

 DiscountFilter filter =(DiscountFilter) new DiscountFilterCreator().Create(DiscountFilterType.normal, "wow"); 
BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47