#c# #entity-framework #c#-7.3
#c# #entity-framework #c #-7.3
Вопрос:
я хотел бы знать, есть ли мнение, как объединить 2 случая моего переключателя, которые почти одинаковы, но один имеет значение, равное нулю, а второй — нет.
switch (rangeA)
{
case Range<int> intRangeA:
{
if (rangeB is Range<int> intRangeB)
{
return intRangeA.ValueFrom <= intRangeB.ValueTo amp;amp; intRangeA.ValueTo >= intRangeB.ValueFrom;
}
return false;
}
case Range<int?> intRangeA:
{
if (rangeB is Range<int?> intRangeB)
{
return intRangeA.ValueFrom <= intRangeB.ValueTo amp;amp; intRangeA.ValueTo >= intRangeB.ValueFrom;
}
return false;
}
}
Комментарии:
1. Ваш код компилируется и выполняется успешно ? В чем конкретно ваша проблема?
2. Мне не нравится, что у меня есть 2 «одинаковых» случая
3. О, так вы хотите объединить два случая, а не разделить их?
4. ах, да, моя вина… извиняюсь за неправильное слово
5.
if
Предложения также соответствуют шаблону. Вы могли бы включить их вcase
предложение вместо того, чтобы повторять одну и ту же проверку каждый раз, сопоставляя с(rangeA,rangeB)
tupple.
Ответ №1:
Это скорее зависит от того, каков тип данных rangeA
and rangeB
.
Предполагая, что это так object
, вы можете сделать что-то вроде этого. Он будет генерировать исключение во время выполнения, если вы создадите Range<Something non-comparable>
для него вызов then ContainsInclusive
. Вы можете добавить дополнительную проверку для этого, если хотите, но это становится немного запутанным, поскольку Nullable<T>
не реализует никаких интерфейсов, поэтому вам придется прибегнуть к рефлексии.
public class Program
{
public static void Main()
{
Foo(new Range<int>() { ValueFrom = 1, ValueTo = 10 }, new Range<int>() { ValueFrom = 0, ValueTo = 10 });
Foo(new Range<int?>() { ValueFrom = 1, ValueTo = 10 }, new Range<int?>() { ValueFrom = 0, ValueTo = 10 });
}
private static bool Foo(object rangeA, object rangeB)
{
return (rangeA, rangeB) switch
{
(Range<int> a, Range<int> b) => b.ContainsInclusive(a),
(Range<int?> a, Range<int?> b) => b.ContainsInclusive(a),
_ => false,
};
}
}
public class Range<T>
{
public T ValueFrom { get; set; }
public T ValueTo { get; set; }
public bool ContainsInclusive(Range<T> other)
{
return Comparer<T>.Default.Compare(other.ValueFrom, this.ValueTo) <= 0 amp;amp;
Comparer<T>.Default.Compare(other.ValueTo, this.ValueFrom) >= 0;
}
}
Если вы не можете использовать новые выражения переключения таким образом, вы потенциально можете сделать что-то вроде:
private static bool Foo(object rangeA, object rangeB)
{
return TryContainsInclusive<int>(rangeA, rangeB) ||
TryContainsInclusive<int?>(rangeA, rangeB);
}
private static bool TryContainsInclusive<T>(object a, object b)
{
if (a is Range<T> rangeA amp;amp; b is Range<T> rangeB)
{
return rangeB.ContainsInclusive(rangeA);
}
return false;
}
Если rangeA
и rangeB
могут быть универсальными типами, вы можете обойтись более простым:
private static bool Foo<T>(Range<T> rangeA, Range<T> rangeB)
{
return rangeB.ContainsInclusive(rangeA);
}
Если rangeA
и rangeB
может быть каким-то базовым Range
типом, то вы можете сделать что-то вроде этого. Опять же, это приведет к сбою во время выполнения, если T
не сопоставимо:
public class Program
{
public static void Main()
{
Foo(new Range<int>() { ValueFrom = 1, ValueTo = 10 }, new Range<int>() { ValueFrom = 0, ValueTo = 10 }).Dump();
Foo(new Range<int?>() { ValueFrom = 1, ValueTo = 10 }, new Range<int?>() { ValueFrom = 0, ValueTo = 10 }).Dump();
}
private static bool Foo(Range rangeA, Range rangeB)
{
return rangeB.ContainsInclusive(rangeA);
}
}
public abstract class Range
{
public abstract bool ContainsInclusive(Range other);
}
public class Range<T> : Range
{
public T ValueFrom { get; set; }
public T ValueTo { get; set; }
public override bool ContainsInclusive(Range other)
{
if (other is Range<T> o)
{
return Comparer<T>.Default.Compare(o.ValueFrom, this.ValueTo) <= 0 amp;amp;
Comparer<T>.Default.Compare(o.ValueTo, this.ValueFrom) >= 0;
}
return false;
}
}
Комментарии:
1. ну, да, ваш последний фрагмент помог.. я все еще занимаюсь проблемой, которую мы используем C # 7.3 в моей компании, но это классное решение, спасибо 🙂
2. @Qhori Смотрите мое редактирование — это еще один потенциальный способ
Ответ №2:
Вы также можете решить эту проблему, используя неабстрактный базовый класс Range
. Range<int>
Range<int?>
Оба и затем присваиваются этому базовому классу.
class Range
{
public object ValueFrom { get; protected set; }
public object ValueTo { get; protected set; }
}
class Range<T> : Range
{
public new T ValueFrom
{
get {
return (T)base.ValueFrom;
}
set {
base.ValueFrom = value;
}
}
public new T ValueTo
{
get {
return (T)base.ValueTo;
}
set {
base.ValueTo = value;
}
}
}
Свойства универсального класса скрывают свойства базового класса. Их установщик защищен. Поэтому установка значений по-прежнему безопасна для типов, поскольку это можно сделать только через универсальный класс.
Затем мое решение состоит в проверке типа значений From и To . Это также хорошо работает для типов с нулевым значением. Если a nullable
равно null, то nullable is int i
уступает false
, в противном случае, если у нас есть a Range<int?>
, он будет присвоен nullable.Value
i
.
Это также позволяет сравнивать a Range<int>
с a Range<int?>
.
Range rangeA = new Range<int> { ValueFrom = 5, ValueTo = 12 };
Range rangeB = new Range<int?> { ValueFrom = 10, ValueTo = 18 };
if (rangeA.ValueFrom is int aFrom amp;amp; rangeA.ValueTo is int aTo amp;amp;
rangeB.ValueFrom is int bFrom amp;amp; rangeB.ValueTo is int bTo) {
return aFrom <= bTo amp;amp; aTo >= bFrom;
}
return false;
Возможным улучшением является наличие строго типизированной резервной переменной в общем варианте:
private T _valueFrom;
public new T ValueFrom
{
get {
return _valueFrom;
}
set {
base.ValueFrom = _valueFrom = value;
}
}
По крайней мере, возврат значения не требует распаковки при работе с общим диапазоном.
Комментарии:
1. Нет, потому что мне нужен большой коммутатор, где я хочу добавить другие типы данных как десятичные, а лучшая версия уже добавлена.. но спасибо 🙂