spada IConvertible
Zacznijmy z 'łatwego części': upuszczenie IConvertible
. Powodem tego jest to, że chcesz, aby ten kod działał na wszystkich typach, co oznacza, że nie zawsze możesz wpływać na to, że ma on określonego użytkownika (Implies
). Co chcesz zrobić, to co nazywają w C++: template specjalizacji, ale niestety nie jest dostępne w języku C# (jeszcze?):
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
Najprostszym sposobem rozwiązania tego jest użycie multimethods. Można użyć „dynamiczne” słowo kluczowe dla tego:
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);
}
}
A jeśli masz metodę „trzeci”, można po prostu nazwać
Szukałem kilka minut w dziwna rekursywna definicja i nie ma to dla mnie większego sensu ... jeśli i tak masz trzecią metodę pomocy, dlaczego nie nazwać jej bezpośrednio? :-)
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 (nie (T)) Problem
Chociaż powyższe nie ma większego sensu dla mnie, uważam, że całkowicie uzasadnione, aby korzystać z systemu typu i języka aby ci pomóc. Cóż, na pewno można to zrobić i to w jaki sposób to zrobić ... :-)
Niech wprowadzi „nie” klasę z Generic:
public class Not<T>
{
public Not(T val)
{
this.not = val;
}
internal T not;
}
Jeśli mamy nie> sytuacja tutaj chcemy dać - w przeciwnym razie chcemy użyć bezpośrednio.Cóż, możemy to zrobić dość łatwo z niektórymi rozszerzeniami:
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;
}
By to sprawdzić, można zrobić coś podobnego:
var val = new Not<Not<int>>(new Not<int>(2));
var result = val.Optimize();
To działa, ponieważ rozdzielczość przeciążenie odbierze poprawnego połączenia optymalizacji co zapewnia, że zoptymalizujesz Not >>>> na wartość T i tak dalej.
Działa również, ponieważ zawijamy "Not" w klasie otoki, a następnie używamy systemu typu na naszą korzyść.
Wracając do pierwotnego problemu
Zamiast bezpośrednio oceny „zakłada” i „wnioskuje”, dlaczego nie korzystać z tymczasowego obiektu, aby zrobić swoją złą pracę. Możesz użyć przeciążania operatorów (domyślna konwersja jest precyzyjna), aby określić relacje Implies i Infers. Jedynym haczykiem jest to, że ma swoje granice dzięki metodom rozszerzania.
Przeciążenie operatora C# wybierze wtedy najlepszą metodę dopasowania. W pierwszym przypadku będzie to dokładne dopasowanie, w drugim przypadku metoda zostanie domyślnie przekonwertowana, a następnie zostanie wywołana funkcja oceniania. Innymi słowy, nie będzie on stosował przepełnienia, tylko dlatego, że zrobi swoją leniwą ocenę. Gotowy na kod? :-)
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();
}
}
[* Paradox *] (http://www.veterangamers.co.uk/blog/wp-content/uploads/2011/04/paradox.jpg) ... –
To na w tym momencie prawdopodobnie przerzucę się na Prolog. – spender
@spender: To dawno temu, kiedyś napisałem w Prologu. Może odpowiedź z Prologu na rozwiązanie tego problemu? –