2016-03-22 21 views
1

Bu, bu özel durumda çalışan bir yanıtı olan, this question'dan bir uzantıdır. Eğer ben ne yayınlanmıştır eşdeğer yansıma kodu kullanırsanız, o inşaat Türü Ters kısıtlamaları olan jenerikler arasında çıkarsama

public abstract class BaseComparable<TLeft, TRight> 
{ } 

public class LeftComparable<TLeft, TRight> : BaseComparable<TLeft, TRight> where TLeft : IComparable<TRight> 
{ 
    public LeftComparable(TLeft value) { } 
} 

public class RightComparable<TLeft, TRight> : BaseComparable<TLeft, TRight> where TRight : IComparable<TLeft> 
{ 
    public RightComparable(TLeft value) { } 
} 

harika:

Sonra
public static BaseComparable<TLeft, TRight> AsComparableFor<TLeft, TRight>(this TLeft left, TRight right) 
{ 
    if (left is IComparable<TRight>) 
    { 
     var constructor = 
      typeof(LeftComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight)) 
             .GetConstructor(new[] { typeof(TLeft) }); 
     if (constructor != null) 
     { 
      return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left }); 
     } 
    } 
    if (right is IComparable<TLeft>) 
    { 
     var constructor = 
      typeof(RightComparable<,>).MakeGenericType(typeof(TLeft), typeof(TRight)) 
             .GetConstructor(new[] { typeof(TLeft) }); 
     if (constructor != null) 
     { 
      return (BaseComparable<TLeft, TRight>)constructor.Invoke(new object[] { left }); 
     } 
    } 
    throw new ArgumentException(); 
} 

Eğer

class Baz 
{ 
    public int Value { get; set; } 
} 
class Bar : IComparable<Baz> 
{ 
    public int Value { get; set; } 
    int IComparable<Baz>.CompareTo(Baz other) 
    { 
     return Value.CompareTo(other.Value); 
    } 
} 

// .... 

var bar = new Bar { Value = 1 }; 
var baz = new Baz { Value = 1 }; 
var compBaz = baz.AsComparableFor(bar); 
var compBar = bar.AsComparableFor(baz); 
söyleyebiliriz

Benim gerçek kod daha şuna benzer

Harika, tür çıkarsama tam olarak beklendiği gibi çalışır.

//bar.AsComparableFor(baz); 
//baz.AsComparableFor(bar); //Does not compile 

bar.AsComparableFor<Bar, Baz>(baz); 
baz.AsComparableFor<Baz, Bar>(bar); // Does compile 

bu da büyük bir bölümü olarak kütüphane olarak ağrısız yapmaktı:

public static class Comparable 
{ 
    public static BaseComparable<TLeft, TRight> 
        AsComparableFor<TLeft, TRight>(this IComparable<TRight> left, TRight right) 
    where TLeft : IComparable<TRight> 
    { 
     if (left is TLeft) 
     { 
      if (left is IComparable<TRight>) 
      { 
       return new LeftComparable<TLeft, TRight>((TLeft)left); 
      } 
     } 

     throw new InvalidCastException(); 
    } 

    public static BaseComparable<TLeft, TRight> 
        AsComparableFor<TLeft, TRight>(this TLeft left, IComparable<TLeft> right) 
    where TRight : IComparable<TLeft> 
    { 
     if (left is TLeft) 
     { 
      if (right is IComparable<TLeft>) 
      { 
       return new RightComparable<TLeft, TRight>((TLeft)left); 
      } 
     } 

     throw new InvalidCastException(); 
    } 
} 

açıkça tip argümanları ifade etmenizi gerektirir

ancak yukarıda kabul cevabını adaptasyon, Mümkün ve ben biraz tür yenilgi belirtmek zorunda hissediyorum.

Orta zemin var mı? Orijinalin çıkarım gücüyle kabul edilen cevaptan daha temiz ve yansımasız bir kod alabilir miyim?

Düzenleme: full code can be found in this gist.

+0

Karşılaştırılacak özellikleri ("int Değeri") derleme zamanında nasıl biliyorsunuz, ancak yalnızca karşılaştırma zamanında hangi sınıfları karşılaştıracağınızı biliyorsunuz? Bu bir bağlantı kesme gibi görünüyor. Bilgilerini çalışma zamanında eklemek yerine, karşılaştırılabilir sınıfınızı önceden oluşturabileceğiniz gibi görünüyor. Ayrıca, tüm bu tip kontrolleri yapmak çok çirkin. Belki de bu kaçınılmaz değildir, ama yikes. Bunu daha da somut hale getirebilseydim. Neden farklı sınıfları karşılaştırmaya gerek var? – ErikE

+0

@ErikE '[Sol | Sağ] Karşılaştırılabilir 've' Karşılaştırılabilir 'kitaplık sınıflarıdır. 'Bar' ve 'Baz', kullanıcı koduyla ilgili örneklerden sadece birkaçı. – RoadieRich

cevap

1

Ben orijinalin tür kesmesi gücü ile kabul edilen yanıt dan temizleyici, yansımasız kodu alabilir miyim?

Yapamazsınız. Aslında kabul edilen cevap iyi değildir çünkü değer tipi boksu içerir.

Yine, yansımadan kaçınamazsınız.

: Ne olsa yapabileceği EqualityComparer<T>.Default implementation, Comparer<T>.Default vb aynı teknik kullanılarak yansıtma tek fark yerine tekil örneğini oluşturmak yerine, biz bir tekil fabrika temsilci oluştururuz olurdu minimize etmektir
+0

Bu şekilde, benimseme versiyonumda, "Bu, çerçeve nasıl yapıyor?" Dışında bu şekilde tercih edilmesinin bir sebebi var - kendi içinde, iyi bir nedeni olmalı? – RoadieRich

+0

Performans. çifti başına yalnızca bir kez yansıyor. –

+0

Ah, bu yüzden dolaylı olarak önbelleğe almayı/not almayı ... eklemeyi düşündüğüm bir şeydi. – RoadieRich