巧妙地添加两个对象

问题描述 投票:2回答:5

我正在尝试制作如下方法。 它只添加两个给定的对象并返回。

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);
c# .net system.reflection
5个回答
2
投票

最接近你可以使用标准的.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
投票

添加两个对象是不可能的,因为没有任何可以添加的对象。

这就像你想要“某事”添加“东西”并期望有人用精确答案回答你的问题 - 这是不可能的。

object没有任何字段或属性,所以你想如何添加它们?

除非你考虑到某种基于真实类型添加objects的一般规则,否则它将成为可能:你必须检查输入参数的类型然后在(相当)巨大的switch语句中返回适当的结果(例如。字符串的连接,整数的简单加法......)。


0
投票

你尝试过泛型,但有两件事:

  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
投票

更新

似乎这样也行不通

Limitations of Xamarin.iOS

没有动态代码生成

由于iOS内核阻止应用程序动态生成代码,因此Xamarin.iOS不支持任何形式的动态代码生成。这些包括:

  • System.Reflection.Emit不可用。
  • 不支持System.Runtime.Remoting。
  • 不支持动态创建类型(没有Type.GetType(“MyType`1”)),虽然查找现有类型(例如Type.GetType(“System.String”),但工作得很好)。必须在编译时在运行时注册反向回调

然而

Why does LambdaExpression.Compile() work on iOS (Xamarin)?

在支持代码生成的平台上,使用基于Reflection.Emit的LambdaCompiler

如果那不可用,则使用解释器解释表达式。例如,有些类可以解释ConstantAdd

原版的

我不确定你可以从中得到多少里程数,但你可以使用表达式

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
投票

反射可用于遍历两个对象的属性,检查名称等价和数字数据类型,然后以完全通用的方式修改属性值:

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)
                            { }
                        }
                    }
                }
            }
© www.soinside.com 2019 - 2024. All rights reserved.