我正在尝试制作如下方法。 它只添加两个给定的对象并返回。
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);
最接近你可以使用标准的.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
添加两个对象是不可能的,因为没有任何可以添加的对象。
这就像你想要“某事”添加“东西”并期望有人用精确答案回答你的问题 - 这是不可能的。
object
没有任何字段或属性,所以你想如何添加它们?
除非你考虑到某种基于真实类型添加object
s的一般规则,否则它将成为可能:你必须检查输入参数的类型然后在(相当)巨大的switch
语句中返回适当的结果(例如。字符串的连接,整数的简单加法......)。
你尝试过泛型,但有两件事:
我将有一个泛型函数,并将它传递给Add / Combine函数,可以为不同类型定义。似乎是一种更清洁的方法。
public T Add<T1, T2, T>(T1 firstObject, T2 secondObject, Func<T1,T2,T>Combine)
{
var result = Combine(firstObject, secondObject);
return result;
}
更新
似乎这样也行不通
没有动态代码生成
由于iOS内核阻止应用程序动态生成代码,因此Xamarin.iOS不支持任何形式的动态代码生成。这些包括:
然而
Why does LambdaExpression.Compile() work on iOS (Xamarin)?
在支持代码生成的平台上,使用基于Reflection.Emit的
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()));
反射可用于遍历两个对象的属性,检查名称等价和数字数据类型,然后以完全通用的方式修改属性值:
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)
{ }
}
}
}
}