Умный способ добавить два объекта

2

Я пытаюсь сделать какой-то метод, как показано ниже.
Он просто добавляет два заданных объекта и возвращает.

object add(object a, object b);

Я уже пробовал это с dynamic ключевым словом. К сожалению, этот не работает на iOS. (платформа не допускает генерацию кода во время выполнения)

dynamic add(dynamic a, dynamic b) => a + b;

Итак, вот моя вторая попытка, и я понял, что это будет чертовски так.

private static HybInstance Add(HybInstance a, HybInstance b)
{
    if (a.Is<Int32>()) return AddInt32(a, b);
    /* and so on... */  
}
private static HybInstance AddInt32(HybInstance a, HybInstance b)
{
    Int32 ia = a.As<Int32>();

    if (b.Is<Int16>()) return HybInstance.Int(ia + b.As<Int32>());
    if (b.Is<Int32>()) return HybInstance.Int(ia + b.As<Int32>());
    if (b.Is<Int64>()) return HybInstance.Int64(ia + b.As<Int64>());
    if (b.Is<float>()) return HybInstance.Float(ia + b.As<float>());

    throw new SemanticViolationException($"");
}

// the method should support custom operators too
private static MethodInfo GetAddMethod(HybInstance left) {
    return left.GetMethods("op_Addition").FirstOrDefault();
}

Есть ли более умный способ добавить два объекта?


дополнение:

Вот несколько примеров того, что я хочу сделать. Просто добавьте любые объекты или создайте исключение, если это невозможно.

add(1, 1); // 2
add(1, "b"); // exception

add("a", "b"); // "ab"

// and this one also should be work
add(some_class_with_operator_overloading, 10);
  • 0
    Хорошо, теперь это имеет больше смысла
  • 0
    @MichaelRandall Я добавил примеры
Показать ещё 2 комментария
Теги:
system.reflection

5 ответов

2

IConvertible использованию стандартных типов .NET является, вероятно, IConvertible:

 static IConvertible Add (IConvertible a, IConvertible b)
 {
     if (a is string) return a.ToString() + b;
     if (b is string) return a + b.ToString();
     // other special cases here
     return a.ToDouble(CultureInfo.CurrentCulture) + b.ToDouble(CultureInfo.CurrentCulture);
 }

 static void Main(string[] args)
 {
     IConvertible a = 1;
     IConvertible b = 2;
     IConvertible s = "string";

     Console.WriteLine(Add(a, b));
     Console.WriteLine(Add(s, s));
     Console.WriteLine(Add(a, s));
 }

Производит

3
stringstring
1string
  • 0
    Хорошее решение, до сих пор не знал интерфейс!
0
 public static void AddObjects(object oFrom, object oTo)
        {
            if (oFrom != null && oTo != null)
            {
                foreach (System.Reflection.PropertyInfo f in oFrom.GetType().GetProperties())
                {
                    if ((oTo).GetType().GetProperty(f.Name) != null)
                    {
                        try
                        {
                            string sType = f.GetType().ToString().ToLower();
                            if (sType==("int") )
                            {                              
                                oFrom.GetType().GetProperty(f.Name).SetValue(oFrom, (int)(f.GetValue(oFrom)) + (int)(f.GetValue(oTo)));
                            }
                            if (sType=="int32" )
                            {
                                oFrom.GetType().GetProperty(f.Name).SetValue(oFrom, (Int32)(f.GetValue(oFrom)) + (Int32)(f.GetValue(oTo)));
                            }
                            if (sType==("int64") )
                            {
                                oFrom.GetType().GetProperty(f.Name).SetValue(oFrom, (Int64)(f.GetValue(oFrom)) + (Int64)(f.GetValue(oTo)));
                            }

                            // keep adding for all numeirc types.  maybe theres a better way?
                        }
                        catch (Exception ex)
                        { }
                    }
                }
            }
        }
  • 0
    int и int32 - это одно и то же. Не то, чтобы я пошел с этим подходом, но почему все сравнения строк? Type type = f.GetType(); if(type == typeof(int)) { ... } или, возможно, даже лучше (если c # 7+) использовать switch сопоставления с образцом
  • 0
    Да, хороший комментарий. Я уверен, что есть более эффективный способ сделать это
0

Вы пробовали с дженериками, хотя 2 вещи:

  1. Вы оборачиваете разные объекты в одну и ту же оболочку, кажется, это проблема дизайна, но вы оставите ее, так как я не знаю больше.
  2. Большая часть int может быть непосредственно изменена на Int64, и тогда не будет так много особых случаев

У меня была бы универсальная функция, и я бы передал ей функцию Add/Combine, которая может быть определена для разных типов. Кажется, более чистый подход.

  public  T Add<T1, T2, T>(T1 firstObject, T2 secondObject, Func<T1,T2,T>Combine)
    {
        var result = Combine(firstObject, secondObject);
        return result;
    }
  • 0
    Это просто перемещение проблемы в функцию Combine
  • 0
    @Magnus думаю, что у ОП уже есть решение, это всего лишь попытка найти более чистое решение, как правило, избегая огромной ветви чего-то еще, что для меня было бы чище
0

Невозможно добавить два объекта, потому что нет ничего об объектах, которые можно добавить.

Это как если бы вы хотели добавить "что-то" к "чему-то" и ожидали, что кто-то ответит на ваш вопрос точным ответом - это невозможно.

object нет полей или свойств, так как бы вы хотели их добавить?

Если вы не имеете в виду какое-то общее правило добавления object основанное на их реальном типе, тогда это станет возможным: вам придется проверять тип входных параметров, а затем в (скорее) огромном операторе switch возвращать соответствующий результат (например, конкатенация для строк, простое сложение для целых чисел...).

  • 0
    На самом деле, это не невозможно, моя первая версия кода (с dynamic ) делает именно то, что я хочу.
0

Обновить

Похоже, это тоже не сработает

Ограничения Xamarin.iOS

Нет динамической генерации кода

Поскольку ядро iOS не позволяет приложению динамически генерировать код, Xamarin.iOS не поддерживает какую-либо форму динамического генерирования кода. Они включают:

  • System.Reflection.Emit недоступен.
  • Нет поддержки System.Runtime.Remoting.
  • Нет поддержки для динамического создания типов (нет Type.GetType("MyType'1")), хотя поиск существующих типов (например, Type.GetType("System.String") работает нормально). Обратные обратные вызовы должны быть зарегистрированы во время выполнения во время компиляции.

тем не мение

Почему LambdaExpression.Compile() работает на iOS (Xamarin)?

На платформах, которые поддерживают генерацию кода, используется LambdaCompiler основе LambdaCompiler.

Если это недоступно, выражение интерпретируется с использованием интерпретатора. Например, существуют классы, которые интерпретируют Constant и Add.

оригинал

Я не уверен, сколько пробега вы могли бы извлечь из этого, но вы могли бы использовать выражения

public static object Add<T,T2>(T a,T2 b)
{
   var paramA = Expression.Parameter(typeof(T), "a");
   var paramB = Expression.Parameter(typeof(T2), "b");
   var body = Expression.Add(Expression.Convert(paramA, paramB.Type), paramB);
   var add = Expression.Lambda<Func<T, T2, T2>>(body, paramA, paramB).Compile();
   return add(a, b);
}

Предполагается, что он будет пытаться преобразовать во второй тип параметра и вернуть этот тип.

Очевидно, что любому классу понадобятся соответствующие операторы

Дано

public struct Test
{
   // user-defined conversion from Fraction to double
   public static implicit operator int(Test f)
   {
      return 10;
   }
   public static implicit operator Test(int i)
   {
      return new Test();
   }
   // overload operator *
   public static Test operator +(Test a, Test b)
   {
      return new Test();
   }

}

пример

Console.WriteLine(Add(1, 2));
Console.WriteLine(Add(1, 2.0));
Console.WriteLine(Add(1, new Test()));
  • 0
    Работает ли компиляция выражений на iOS?
  • 0
    @ LasseVågsætherKarlsen крутой вопрос, я понятия не имею, хотя
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню