丢弃 IConvertible
让我们从“简单的部分”开始:删除IConvertible
. 您需要它的原因是因为您希望此代码适用于所有类型,这意味着您不能总是影响它具有某个成员 ( Implies
)。您想要做的是他们在 C++ 中所说的:模板专业化,但不幸的是在 C# 中不可用(还没有?):
static bool Implies<T>(T premise, T conclusion) where T : IConvertible
{
var x = premise.ToUInt64(null);
return x == (x & conclusion.ToUInt64(null));
}
static bool Implies<T>(T premise, T conclusion) where T : Foobar
{
// other fancy logic
}
// and so on
解决这个问题的最简单方法是使用多方法。您可以为此使用“动态”关键字:
public partial class Implications
{
internal static bool CheckImplies<T>(T lhs, T rhs)
{
return Implies((dynamic)lhs, (dynamic)rhs);
}
public static bool Implies(int lhs, int rhs)
{
return lhs == (lhs & rhs);
}
// your other implies thingies implement this same partial class
}
public static partial class LogicExtensions
{
public static bool Implies<T>(this T premise, T conclusion, Paradox<T> predicate = null)
{
if (null == predicate)
return conclusion.Infers(premise, Implies);
if (Infers != predicate)
return predicate(premise, conclusion);
return Implications.CheckImplies(premise, conclusion);
}
public static bool Infers<T>(this T premise, T conclusion, Paradox<T> predicate = null)
{
if (null == predicate)
return premise.Implies(conclusion, Infers);
if (Implies != predicate)
return predicate(premise, conclusion);
return Implications.CheckImplies(premise, conclusion);
}
}
如果你有“第三种”方法,你可以简单地调用它
我已经看了几分钟奇怪的递归定义,它对我来说真的没有意义......如果你有第三个辅助方法,为什么不直接调用它呢?:-)
public static bool Implies<T>(this T premise, T conclusion)
{
return Implications.CheckImplies(premise, conclusion);
}
public static bool Infers<T>(this T premise, T conclusion)
{
return Implications.CheckImplies(conclusion, premise);
}
not(not(T)) 问题
虽然以上对我来说没有多大意义,但我发现使用类型系统和语言来帮助你一点是完全合理的。好吧,当然你可以做到这一点,这就是我会这样做...... :-)
让我们介绍一个带有泛型的“Not”类:
public class Not<T>
{
public Not(T val)
{
this.not = val;
}
internal T not;
}
如果我们这里有一个 Not> 的情况,我们想给 - 否则,我们想直接使用。好吧,我们可以通过一些扩展轻松做到这一点:
public static T Optimize<T>(this Not<Not<T>> var)
{
return Optimize(var.not.not);
}
public static T Optimize<T>(this T var)
{
return var;
}
要对其进行测试,您可以执行类似的操作:
var val = new Not<Not<int>>(new Not<int>(2));
var result = val.Optimize();
这是可行的,因为重载解决方案将选择正确的 Optimize 调用,从而确保您将 Not>>>> 优化为 T 值等等。
它也有效,因为我们将“Not”包装在一个包装类中,然后使用类型系统来发挥我们的优势。
回到最初的问题
与其直接评估“暗示”和“推断”,不如使用临时对象来做你的坏事。您可以使用运算符重载(准确地说是隐式转换)来指定 Implies 和 Infers 如何关联。唯一的问题是它对扩展方法有限制。
然后 C# 运算符重载将选择最佳匹配方法。在第一种情况下,这将是完全匹配,在第二种情况下,方法将被隐式转换,然后调用 Evaluate。换句话说,它不会堆栈溢出,仅仅是因为它会懒惰地进行评估。准备好代码了吗?:-)
public class Implies<T>
{
public Implies(T premise, T conclusion)
{
this.premise = premise;
this.conclusion = conclusion;
}
public T premise;
public T conclusion;
public static implicit operator Infers<T>(Implies<T> src)
{
return new Infers<T>(src.conclusion, src.premise);
}
}
public class Infers<T>
{
public Infers(T premise, T conclusion)
{
this.premise = premise;
this.conclusion = conclusion;
}
public T premise;
public T conclusion;
public static implicit operator Implies<T>(Infers<T> src)
{
return new Implies<T>(src.conclusion, src.premise);
}
}
public static partial class LogicExtensions
{
public static Implies<T> Implies<T>(this T premise, T conclusion)
{
return new Implies<T>(premise, conclusion);
}
public static Infers<T> Infers<T>(this T premise, T conclusion)
{
return new Infers<T>(premise, conclusion);
}
}
public class Foo
{
// The things you wish to implement :-)
public static bool Evaluate(Implies<int> impl)
{
return impl.premise == (impl.conclusion & impl.premise);
}
static void Main(string[] args)
{
Implies<int> impl= 0.Implies(2); // will be called directly
Infers<int> impl2 = 0.Infers(2); // will be converted
Console.WriteLine("Res: {0} {1}", Evaluate(impl), Evaluate(impl2));
Console.ReadLine();
}
}