Genel yöntemimi sayısal türlerle sınırlayan bir kısıtlama var mı?


364

Herkes jenerikler ile genel bir tür argümanını Tsadece sınırlamak için bir yol olup olmadığını söyleyebilir :

  • Int16
  • Int32
  • Int64
  • UInt16
  • UInt32
  • UInt64

whereAnahtar kelimenin farkındayım , ancak yalnızca bu türler için bir arayüz bulamıyorum ,

Gibi bir şey:

static bool IntegerFunction<T>(T value) where T : INumeric 

2
Şimdi bunun gerçekleştirilmesine izin verecek çeşitli C # önerileri var, ancak AFAIK bunların hiçbiri ön keşifler / tartışmalardan başka değil. Bkz Şekilleri ve Uzantıları: Exploration , Keşif: Rolleri, uzatma arayüzleri ve statik arayüz üyeleri , Şampiyon "Tür Sınıfları (Kavramları aka Yapısal Jenerik Kısıtlamaları)" ve Öneri: Genel türleri operatörleri desteklemelidir
Chris Yungmann

Yanıtlar:


140

C # bunu desteklemiyor. Hejlsberg, Bruce Eckel ile bir röportajda bu özelliğin uygulanmamasının nedenlerini açıkladı :

Eklenen karmaşıklığın, elde ettiğiniz küçük verime değeceği açık değildir. Yapmak istediğiniz bir şey kısıtlama sisteminde doğrudan desteklenmiyorsa, bunu bir fabrika modeliyle yapabilirsiniz. Matrix<T>Örneğin, bir noktaya sahip olabilirsiniz ve bunun Matrixiçin bir nokta ürün yöntemi tanımlamak istersiniz. Yani sonuçta ne kadar çarpın iki anlamamız gerekir araçlarının elbette Ten azından değilse, bir kısıtlama olarak söyleyemeyiz ler, ancak Tolduğu int, doubleya da float. Ama yapabileceğiniz şey, Matrixargüman olarak a Calculator<T>ve in Calculator<T>adlı bir yönteme sahip olmaktır multiply. Sen onu uygulamaya git ve onu geç Matrix.

Ancak, bu, kullanıcının kullanmak istedikleri Calculator<T>her biri için kendi uygulamalarını sağlaması gereken oldukça kıvrımlı bir koda yol açar T. Genişletilebilir olması gerekmediği sürece, yani intve gibi sabit sayıda türü desteklemek doubleistiyorsanız, nispeten basit bir arayüzle kurtulabilirsiniz:

var mat = new Matrix<int>(w, h);

( Bir GitHub Gist'te minimum uygulama. )

Ancak, kullanıcının kendi özel türlerini sağlayabilmesini istediğiniz anda, kullanıcının kendi Calculatorörneklerini sağlayabilmesi için bu uygulamayı açmanız gerekir . Örneğin, özel ondalık kayan nokta uygulaması kullanan bir matris başlatmak için DFPşu kodu yazmanız gerekir:

var mat = new Matrix<DFP>(DfpCalculator.Instance, w, h);

... ve tüm üyeleri uygulamak DfpCalculator : ICalculator<DFP>.

Ne yazık ki aynı sınırlamaları paylaşan bir alternatif, Sergey Shandar'ın cevabında tartışıldığı gibi politika sınıflarıyla çalışmaktır .


25
btw, MiscUtil tam olarak bunu yapan genel bir sınıf sağlar; Operator/ Operator<T>; yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html
Marc Gravell

1
@ Mark: iyi yorum. Ancak, açık olmak gerekirse, Hejlsberg'in kod üretiminden, Operator<T>kodda yaptığınız gibi soruna bir çözüm olarak bahsettiğini sanmıyorum (görüşme, Expressionsçerçevenin varlığından çok önce verilmiş olduğundan, kullanımı Reflection.Emit) - ve onun geçici çözümüyle gerçekten ilgilenirim .
Konrad Rudolph

@Konrad Rudolph: Bence benzer bir sorunun cevabı Hejlsberg'in geçici çözümünü açıklıyor. Diğer jenerik sınıf soyutlaştırılmıştır. Desteklemek istediğiniz her tür için diğer genel sınıfı uygulamanızı gerektirdiğinden, bu kod yinelenen kodla sonuçlanır, ancak yalnızca orijinal genel sınıfı desteklenen bir türle başlatabileceğiniz anlamına gelir.
Ergwun

14
Heijsberg'in ifadesini kabul etmiyorum "Yani bir anlamda, C ++ şablonları gerçekte yazılmamış veya gevşek yazılmıştır. Oysa C # jenerikleri güçlü bir şekilde yazılmıştır." Bu gerçekten Pazarlama BS C # teşvik etmek. Güçlü / Zayıf yazmanın, tanı kalitesiyle ilgisi yoktur. Aksi takdirde: İlginç bul.
Sebastian Mach

100

Bu sorunun popülaritesi ve böyle bir fonksiyonun arkasındaki ilgi göz önüne alındığında, henüz T4 ile ilgili bir cevap olmadığını görmek beni şaşırttı.

Bu örnek kodda, derleyici jeneriklerle sahnelerin arkasında hemen hemen ne yaptığını yapmak için güçlü şablonlama motorunu nasıl kullanabileceğinize dair çok basit bir örnek göstereceğim.

Çemberlerden geçmek ve derleme zamanı kesinliğinden ödün vermek yerine, istediğiniz her tür için istediğiniz işlevi üretebilir ve buna göre kullanabilirsiniz (derleme zamanında!).

Bunu yapmak için:

  • GenericNumberMethodTemplate.tt adlı yeni bir Metin Şablonu dosyası oluşturun .
  • Otomatik oluşturulan kodu kaldırın (çoğunu koruyacaksınız, ancak bazılarına gerek yoktur).
  • Aşağıdaki snippet'i ekleyin:
<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>

<# Type[] types = new[] {
    typeof(Int16), typeof(Int32), typeof(Int64),
    typeof(UInt16), typeof(UInt32), typeof(UInt64)
    };
#>

using System;
public static class MaxMath {
    <# foreach (var type in types) { 
    #>
        public static <#= type.Name #> Max (<#= type.Name #> val1, <#= type.Name #> val2) {
            return val1 > val2 ? val1 : val2;
        }
    <#
    } #>
}

Bu kadar. Artık işiniz bitti.

Bu dosyayı kaydetmek otomatik olarak bu kaynak dosyaya derler:

using System;
public static class MaxMath {
    public static Int16 Max (Int16 val1, Int16 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static Int32 Max (Int32 val1, Int32 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static Int64 Max (Int64 val1, Int64 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt16 Max (UInt16 val1, UInt16 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt32 Max (UInt32 val1, UInt32 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt64 Max (UInt64 val1, UInt64 val2) {
        return val1 > val2 ? val1 : val2;
    }
}

Senin içinde mainyöntemle size derleme zamanı kesinlik olduğunu doğrulayabilirsiniz:

namespace TTTTTest
{
    class Program
    {
        static void Main(string[] args)
        {
            long val1 = 5L;
            long val2 = 10L;
            Console.WriteLine(MaxMath.Max(val1, val2));
            Console.Read();
        }
    }
}

resim açıklamasını buraya girin

Bir açıklamadan öteye geçeceğim: hayır, bu KURU prensibinin ihlali değildir. NEM ALMA ilkesi, uygulamanın birden fazla yerde kod kopyalamasını engellemek için uygulamanın korunmasını zorlaştırır.

Burada durum böyle değil: Eğer bir değişiklik istiyorsanız, sadece şablonu değiştirebilirsiniz (tüm nesil için tek bir kaynak!) Ve bitti.

Kendi özel tanımlarınızla kullanmak için, oluşturulan kodunuza bir ad alanı bildirimi ekleyin (kendi uygulamanızı tanımlayacağınızla aynı olduğundan emin olun) ve sınıfı olarak işaretleyin partial. Daha sonra, bu derlemeyi şablon dosyanıza ekleyin, böylece nihai derlemeye dahil edilir:

<#@ import namespace="TheNameSpaceYouWillUse" #>
<#@ assembly name="$(TargetPath)" #>

Dürüst olalım: Bu çok güzel.

Feragatname: Bu örnek, .NET'te Metaprogramming'den Kevin Hazzard ve Manning Publications'dan Jason Bock tarafından büyük ölçüde etkilendi .


Bu oldukça havalı, ancak yöntemlerin Tçeşitli IntXsınıflardan veya sınıflardan miras alan bazı genel türleri kabul etmesini sağlamak için bu çözümü değiştirmek mümkün müdür ? Bu çözümü beğendim çünkü zaman kazandırıyor, ancak% 100 sorunu çözmek için (C # bu tür bir kısıtlama için yerleşik olmasına rağmen güzel olmasa da) oluşturulan yöntemlerin her biri hala genel olmalı IntXXsınıflardan birinden miras kalan türde bir nesne döndürebilirler .
Zachary Kniebel

1
@ZacharyKniebel: Türler yapılardır, IntXXyani miras almayı desteklemezler . Ve bunu yapsa bile, Liskov ikame prensibi (SOLID deyiminden bildiğiniz gibi) geçerlidir: yöntem, tanım olarak bir çocuk olarak tanımlanmışsa Xve tanım başına bir çocuksa, herhangi birinin yerine bu yönteme geçilebilmelidir. temel türü. YXY
Jeroen Vannevel

1
Stackoverflow.com/questions/32664/… ilkelerini kullanan bu geçici çözüm , sınıflar oluşturmak için T4'ü kullanır.
Sergey Shandar

2
Politika tabanlı çözümlerin aksine yerleşik integral türlerinin çalışma verimliliğini koruduğu için bu çözüm için +1. Yerleşik CLR işleçlerini (Add gibi) ek (muhtemelen sanal) bir yöntemle çağırmak, birçok kez kullanıldığında (matematik kitaplıklarında olduğu gibi) performansı ciddi şekilde etkileyebilir. Ve integral tiplerinin sayısı sabit olduğundan (ve devralınamayacağından) sadece hata düzeltmeleri için kodu yeniden oluşturmanız gerekir.
Attila Klenik

1
Çok havalı ve kullanmaya başlamak üzereydim, sonra yeniden düzenleme için Resharper'a ne kadar bağımlı olduğumu hatırladım ve refactor'u T4 şablonu aracılığıyla yeniden adlandıramazsınız. Kritik değil, dikkate almaya değer.
bradgonesurfing

86

Bunun için bir kısıtlama yok. Sayısal hesaplamalar için jenerik kullanmak isteyen herkes için gerçek bir konudur.

Daha ileri gidip ihtiyacımız olduğunu söylerdim

static bool GenericFunction<T>(T value) 
    where T : operators( +, -, /, * )

Ya da

static bool GenericFunction<T>(T value) 
    where T : Add, Subtract

Maalesef yalnızca arabirimleriniz, temel sınıflarınız ve anahtar kelimeleriniz struct(değer türü classolmalıdır ), (başvuru türü new()olmalıdır ) ve (varsayılan oluşturucuya sahip olmalıdır)

Numarayı burada kod projesinde olduğuINullable<T> gibi başka bir şeye (benzeri ) sarabilirsiniz .


Kısıtlamayı çalışma zamanında uygulayabilirsiniz (işleçleri yansıtarak veya türleri denetleyerek), ancak genel olarak jenerik olma avantajını kaybetmez.


2
MiscUtil'in jenerik operatörler için desteğini gördünüz mü merak ediyorum ... yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html
Marc Gravell

10
Evet - Jon Skeet bana bir süre önce başka bir şey için işaret etti (ama bu yılki yanıttan sonra) - akıllıca bir fikir, ama yine de uygun kısıtlama desteği istiyorum.
Keith

1
Bekle, where T : operators( +, -, /, * )yasal C # mı? Acemi soru için özür dilerim.
kdbanman

@kdbanman Ben öyle düşünmüyorum. Keith, C # 'ın OP'nin sorduğunu desteklemediğini ve yapabilmemiz gerektiğini where T : operators( +, -, /, * ), ancak yapamayacağımızı önerdiğini söylüyor .
AMTerp

62

Politikaları kullanarak geçici çözüm:

interface INumericPolicy<T>
{
    T Zero();
    T Add(T a, T b);
    // add more functions here, such as multiplication etc.
}

struct NumericPolicies:
    INumericPolicy<int>,
    INumericPolicy<long>
    // add more INumericPolicy<> for different numeric types.
{
    int INumericPolicy<int>.Zero() { return 0; }
    long INumericPolicy<long>.Zero() { return 0; }
    int INumericPolicy<int>.Add(int a, int b) { return a + b; }
    long INumericPolicy<long>.Add(long a, long b) { return a + b; }
    // implement all functions from INumericPolicy<> interfaces.

    public static NumericPolicies Instance = new NumericPolicies();
}

Algoritmalar:

static class Algorithms
{
    public static T Sum<P, T>(this P p, params T[] a)
        where P: INumericPolicy<T>
    {
        var r = p.Zero();
        foreach(var i in a)
        {
            r = p.Add(r, i);
        }
        return r;
    }

}

Kullanımı:

int i = NumericPolicies.Instance.Sum(1, 2, 3, 4, 5);
long l = NumericPolicies.Instance.Sum(1L, 2, 3, 4, 5);
NumericPolicies.Instance.Sum("www", "") // compile-time error.

Çözüm derleme zamanı güvenlidir. CityLizard Framework , .NET 4.0 için derlenmiş bir sürüm sağlar. Dosya lib / NETFramework4.0 / CityLizard.Policy.dll'dir.

Nuget'te de mevcuttur: https://www.nuget.org/packages/CityLizard/ . Bkz. CityLizard.Policy.I yapısı.


Genel parametrelerden daha az işlev bağımsız değişkeni olduğunda bu kalıpla ilgili sorunlar yaşadım. Stackoverflow.com/questions/36048248/…
xvan

kullanmanın bir nedeni var structmı? bunun yerine singleton sınıfı kullanır ve örneği değiştirir public static NumericPolicies Instance = new NumericPolicies();ve bu yapıcıyı eklersem ne olur private NumericPolicies() { }?
M.kazem Akhgary

@ M.kazemAkhgary singleton'u kullanabilirsiniz. Yapıyı tercih ederim. Teoride, derleyici / CLR tarafından optimize edilebilir, çünkü yapı hiçbir bilgi içermez. Singleton durumunda, yine de GC'ye ek baskı ekleyebilecek bir referans ileteceksiniz. Başka bir avantaj, yapı null olamaz :-).
Sergey Shandar

Çok akıllı bir çözüm bulduğunuzu söyleyecektim, ancak çözüm benim için çok sınırlı: Onu kullanacaktım T Add<T> (T t1, T t2), ancak Sum()sadece kendi T türünü parametrelerinden alabildiği zaman çalışıyor, bu mümkün değil başka bir genel işleve gömülü olduğunda.
Tobias Knauss

16

Bu soru biraz SSS sorusudur, bu yüzden bunu wiki olarak gönderiyorum (daha önce benzer yayınladığım için, ancak bu daha eski bir soru); Neyse ...

Hangi .NET sürümünü kullanıyorsunuz? .NET 3.5 kullanıyorsanız , MiscUtil'de genel bir işleçler uygulaması var (serbest vs).

Bu, T Add<T>(T x, T y)farklı türlerde aritmetik gibi yöntemler ve diğer varyantlara sahiptir (DateTime + TimeSpan ) .

Ayrıca, tüm dahili, kaldırılmış ve ısmarlama operatörler için çalışır ve delege performans için önbelleğe alınır.

Bunun neden zor olduğu konusunda bazı ek bilgiler burada .

dynamic(4.0) türünün bu sorunu dolaylı olarak da çözdüğünü bilmek isteyebilirsiniz - ör.

dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect

14

Maalesef, yalnızca bu örnekte where yan tümcesinde yapı belirtebilirsiniz. Özellikle Int16, Int32, vb.

Tek çözüm maalesef sorunun derleme zamanında alınmasını önleyen bir çalışma zamanı kontrolü yapmaktır sanırım. Bu şöyle bir şey olurdu: -

static bool IntegerFunction<T>(T value) where T : struct {
  if (typeof(T) != typeof(Int16)  &&
      typeof(T) != typeof(Int32)  &&
      typeof(T) != typeof(Int64)  &&
      typeof(T) != typeof(UInt16) &&
      typeof(T) != typeof(UInt32) &&
      typeof(T) != typeof(UInt64)) {
    throw new ArgumentException(
      string.Format("Type '{0}' is not valid.", typeof(T).ToString()));
  }

  // Rest of code...
}

Bu biraz çirkin biliyorum, ama en azından gerekli kısıtlamaları sağlar.

Bu uygulama için olası performans etkilerini de inceleyeceğim, belki de daha hızlı bir yol var.


13
Ancak, // Rest of code...kısıtlamalar tarafından tanımlanan işlemlere bağlıysa derleme yapılamayabilir.
Nick

1
Convert.ToIntXX (değer), "// Kodun geri kalanı" nın derlenmesine yardımcı olabilir - en azından IntegerFunction'ın dönüş türü de T türüne gelene kadar çemberlenirsiniz. :-p
yoyo

1; @Nick tarafından verilen nedenden dolayı bu işe yaramıyor. An aritmetik işlemleri yapmaya çalışacağım // Rest of code...gibi value + valueya value * valuebir derleme hatası var.
Mark Amery

13

Muhtemelen yapabileceğiniz en yakın şey

static bool IntegerFunction<T>(T value) where T: struct

Aşağıdakileri yapabileceğinizden emin değilim

static bool IntegerFunction<T>(T value) where T: struct, IComparable
, IFormattable, IConvertible, IComparable<T>, IEquatable<T>

Bu kadar özel bir şey için, neden her tip için aşırı yüklenmeler değil, liste çok kısa ve muhtemelen daha az bellek kaplaması olacak.


6

C # 7.3 ile başlayarak, daha yakın bir yaklaşımı kullanabilirsiniz - bir type parametresinin işaretçi olmayan, nullable olmayan yönetilmeyen bir tür olduğunu belirtmek için yönetilmeyen kısıtlama .

class SomeGeneric<T> where T : unmanaged
{
//...
}

Yönetilmeyen kısıtlama, yapı kısıtlamasını ima eder ve struct veya new () kısıtlamaları ile birleştirilemez.

Aşağıdaki türlerden herhangi biri varsa, tür yönetilmeyen bir türdür:

  • sbyte, bayt, kısa, kısa, int, uint, uzun, ulong, karakter, kayan nokta, çift, ondalık veya bool
  • Herhangi bir numaralandırma türü
  • Herhangi bir işaretçi türü
  • Yalnızca yönetilmeyen türlerde alanlar içeren ve C # 7.3 ve önceki sürümlerde, kullanıcı tanımlı herhangi bir yapı türü yapılandırılmış bir tür değildir (en az bir tür bağımsız değişkeni içeren bir tür)

Daha da kısıtlamak ve ıcomparable eklenti uygulamak gerekmez işaretçi ve kullanıcı tanımlı türlerini ortadan kaldırmak için IComparable yüzden IEquatable <T> ekleyerek enum kısıtlamak, (ancak enum hala IComparable türetilmiştir, kendi koşullara bağlı ileri gidip ve ek arayüzleri ekleyebilirsiniz. yönetilmeyen bu listenin daha kısa tutulmasına izin verir):

    class SomeGeneric<T> where T : unmanaged, IComparable, IEquatable<T>
    {
    //...
    }

Güzel, ama yeterli değil ... Örneğin, kısıtlama DateTimealtına girer unmanaged, IComparable, IEquatable<T>..
Adam Calvet Bohl

Biliyorum ama koşullarınıza bağlı olarak daha ileri gidebilir ve ek arayüzler ekleyebilirsiniz. yönetilmeyen bu listenin daha kısa tutulmasına izin verir. Ben sadece yaklaşım, yönetilmeyen kullanarak yaklaşım gösterdim. Çoğu durumda bu yeterlidir
Vlad Novakovsky

4

Şablonları türlerle sınırlamanın bir yolu yoktur, ancak türe göre farklı eylemler tanımlayabilirsiniz. Genel bir sayısal paketin parçası olarak, iki değer eklemek için genel bir sınıfa ihtiyacım vardı.

    class Something<TCell>
    {
        internal static TCell Sum(TCell first, TCell second)
        {
            if (typeof(TCell) == typeof(int))
                return (TCell)((object)(((int)((object)first)) + ((int)((object)second))));

            if (typeof(TCell) == typeof(double))
                return (TCell)((object)(((double)((object)first)) + ((double)((object)second))));

            return second;
        }
    }

Yazım hatalarının derleme zamanında değerlendirildiğini, bu nedenle if ifadelerinin derleyici tarafından kaldırılacağını unutmayın. Derleyici ayrıca sahte yayınları da kaldırır. Yani derleyici bir şey çözmek için

        internal static int Sum(int first, int second)
        {
            return first + second;
        }

Ampirik bir çözüm sunduğunuz için teşekkür ederiz!
zsf222

Her tür için aynı yöntemi oluşturmakla aynı şey değil mi?
Luis

3

Bu sorunları çözmek için küçük bir kütüphane işlevi oluşturdum:

Onun yerine:

public T DifficultCalculation<T>(T a, T b)
{
    T result = a * b + a; // <== WILL NOT COMPILE!
    return result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Should result in 8.

Yazabilirsiniz:

public T DifficultCalculation<T>(Number<T> a, Number<T> b)
{
    Number<T> result = a * b + a;
    return (T)result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Results in 8.

Kaynak kodu burada bulabilirsiniz: /codereview/26022/improvement-requested-for-generic-calculator-and-generic-number


2

Samjudson ile aynı şeyi merak ediyordum, neden sadece tamsayılara? ve durum böyleyse, istediğiniz tüm türleri tutmak için yardımcı bir sınıf veya bunun gibi bir şey oluşturmak isteyebilirsiniz.

Tüm istediğiniz tamsayılarsa, genel değil, genel değil; veya daha iyisi, türünü kontrol ederek başka herhangi bir türü reddedin.


2

Bunun için henüz 'iyi' bir çözüm yok. Bununla birlikte, Haacked'in yukarıda gösterdiği gibi hipotetik 'INumeric' kısıtlamanız için birçok missfits'i ekarte etmek için tür argümanını önemli ölçüde daraltabilirsiniz.

statik bool IntegerFunction <T> (T değeri) burada T: IComparable, IFormattable, IConvertible, IComparable <T>, IEquatable <T>, struct {...


2

.NET 4.0 ve sonraki bir sürümü kullanıyorsanız, dinamik olarak yöntem bağımsız değişkeni olarak kullanabilirsiniz ve çalışma zamanında geçirilen dinamik bağımsız değişken türünün sayısal / tamsayı türü olup olmadığını denetleyebilirsiniz .

Geçti türü ise dinamiği olduğunu değil sayısal / tamsayı tipi sonra istisna.

Fikri uygulayan örnek bir kısa kod şöyledir:

using System;
public class InvalidArgumentException : Exception
{
    public InvalidArgumentException(string message) : base(message) {}
}
public class InvalidArgumentTypeException : InvalidArgumentException
{
    public InvalidArgumentTypeException(string message) : base(message) {}
}
public class ArgumentTypeNotIntegerException : InvalidArgumentTypeException
{
    public ArgumentTypeNotIntegerException(string message) : base(message) {}
}
public static class Program
{
    private static bool IntegerFunction(dynamic n)
    {
        if (n.GetType() != typeof(Int16) &&
            n.GetType() != typeof(Int32) &&
            n.GetType() != typeof(Int64) &&
            n.GetType() != typeof(UInt16) &&
            n.GetType() != typeof(UInt32) &&
            n.GetType() != typeof(UInt64))
            throw new ArgumentTypeNotIntegerException("argument type is not integer type");
        //code that implements IntegerFunction goes here
    }
    private static void Main()
    {
         Console.WriteLine("{0}",IntegerFunction(0)); //Compiles, no run time error and first line of output buffer is either "True" or "False" depends on the code that implements "Program.IntegerFunction" static method.
         Console.WriteLine("{0}",IntegerFunction("string")); //Also compiles but it is run time error and exception of type "ArgumentTypeNotIntegerException" is thrown here.
         Console.WriteLine("This is the last Console.WriteLine output"); //Never reached and executed due the run time error and the exception thrown on the second line of Program.Main static method.
    }

Tabii ki bu çözüm sadece çalışma zamanında çalışır ancak derleme zamanında asla çalışmaz.

Her zaman derleme zamanında çalışan ve asla çalışma zamanında çalışmayan bir çözüm istiyorsanız, dinamiği aşırı yüklenmiş genel kurucuları yalnızca istenen türdeki argümanları kabul eden ve yapı / sınıfa uygun ad veren bir genel yapı / sınıfla sarmanız gerekir .

Sarılmış dinamiğin her zaman sınıf / yapıya özel üye olması ve yapı / sınıfın tek üyesi olması ve yapı / sınıfın tek üyesinin adı "değer" olması mantıklıdır .

Ayrıca, gerekirse sınıfın / yapının özel dinamik üyesi için istenen türlerle çalışan genel yöntemleri ve / veya işleçleri tanımlamanız ve uygulamanız gerekir.

Ayrıca yapı / sınıf vardır mantıklı özel / benzersiz kabul yapıcı dinamiğini o "değer" olarak adlandırılan tek özel dinamik üyesi ama başlatır argüman olarak değiştirici bu yapıcı taşımaktadır özel tabii ki.

Class / struct hazır olduğunda, argümanın IntegerFunction türünü tanımlanan sınıf / struct olarak tanımlayın.

Fikri uygulayan örnek bir uzun kod şuna benzer:

using System;
public struct Integer
{
    private dynamic value;
    private Integer(dynamic n) { this.value = n; }
    public Integer(Int16 n) { this.value = n; }
    public Integer(Int32 n) { this.value = n; }
    public Integer(Int64 n) { this.value = n; }
    public Integer(UInt16 n) { this.value = n; }
    public Integer(UInt32 n) { this.value = n; }
    public Integer(UInt64 n) { this.value = n; }
    public Integer(Integer n) { this.value = n.value; }
    public static implicit operator Int16(Integer n) { return n.value; }
    public static implicit operator Int32(Integer n) { return n.value; }
    public static implicit operator Int64(Integer n) { return n.value; }
    public static implicit operator UInt16(Integer n) { return n.value; }
    public static implicit operator UInt32(Integer n) { return n.value; }
    public static implicit operator UInt64(Integer n) { return n.value; }
    public static Integer operator +(Integer x, Int16 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, Int32 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, Int64 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt16 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt32 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt64 y) { return new Integer(x.value + y); }
    public static Integer operator -(Integer x, Int16 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, Int32 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, Int64 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt16 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt32 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt64 y) { return new Integer(x.value - y); }
    public static Integer operator *(Integer x, Int16 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, Int32 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, Int64 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt16 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt32 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt64 y) { return new Integer(x.value * y); }
    public static Integer operator /(Integer x, Int16 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, Int32 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, Int64 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt16 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt32 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt64 y) { return new Integer(x.value / y); }
    public static Integer operator %(Integer x, Int16 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, Int32 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, Int64 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt16 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt32 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt64 y) { return new Integer(x.value % y); }
    public static Integer operator +(Integer x, Integer y) { return new Integer(x.value + y.value); }
    public static Integer operator -(Integer x, Integer y) { return new Integer(x.value - y.value); }
    public static Integer operator *(Integer x, Integer y) { return new Integer(x.value * y.value); }
    public static Integer operator /(Integer x, Integer y) { return new Integer(x.value / y.value); }
    public static Integer operator %(Integer x, Integer y) { return new Integer(x.value % y.value); }
    public static bool operator ==(Integer x, Int16 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int16 y) { return x.value != y; }
    public static bool operator ==(Integer x, Int32 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int32 y) { return x.value != y; }
    public static bool operator ==(Integer x, Int64 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int64 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt16 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt16 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt32 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt32 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt64 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt64 y) { return x.value != y; }
    public static bool operator ==(Integer x, Integer y) { return x.value == y.value; }
    public static bool operator !=(Integer x, Integer y) { return x.value != y.value; }
    public override bool Equals(object obj) { return this == (Integer)obj; }
    public override int GetHashCode() { return this.value.GetHashCode(); }
    public override string ToString() { return this.value.ToString(); }
    public static bool operator >(Integer x, Int16 y) { return x.value > y; }
    public static bool operator <(Integer x, Int16 y) { return x.value < y; }
    public static bool operator >(Integer x, Int32 y) { return x.value > y; }
    public static bool operator <(Integer x, Int32 y) { return x.value < y; }
    public static bool operator >(Integer x, Int64 y) { return x.value > y; }
    public static bool operator <(Integer x, Int64 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt16 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt16 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt32 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt32 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt64 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt64 y) { return x.value < y; }
    public static bool operator >(Integer x, Integer y) { return x.value > y.value; }
    public static bool operator <(Integer x, Integer y) { return x.value < y.value; }
    public static bool operator >=(Integer x, Int16 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int16 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Int32 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int32 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Int64 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int64 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt16 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt16 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt32 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt32 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt64 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt64 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Integer y) { return x.value >= y.value; }
    public static bool operator <=(Integer x, Integer y) { return x.value <= y.value; }
    public static Integer operator +(Int16 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(Int32 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(Int64 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt16 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt32 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt64 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator -(Int16 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(Int32 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(Int64 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt16 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt32 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt64 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator *(Int16 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(Int32 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(Int64 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt16 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt32 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt64 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator /(Int16 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(Int32 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(Int64 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt16 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt32 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt64 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator %(Int16 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(Int32 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(Int64 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt16 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt32 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt64 x, Integer y) { return new Integer(x % y.value); }
    public static bool operator ==(Int16 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int16 x, Integer y) { return x != y.value; }
    public static bool operator ==(Int32 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int32 x, Integer y) { return x != y.value; }
    public static bool operator ==(Int64 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int64 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt16 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt16 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt32 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt32 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt64 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt64 x, Integer y) { return x != y.value; }
    public static bool operator >(Int16 x, Integer y) { return x > y.value; }
    public static bool operator <(Int16 x, Integer y) { return x < y.value; }
    public static bool operator >(Int32 x, Integer y) { return x > y.value; }
    public static bool operator <(Int32 x, Integer y) { return x < y.value; }
    public static bool operator >(Int64 x, Integer y) { return x > y.value; }
    public static bool operator <(Int64 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt16 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt16 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt32 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt32 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt64 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt64 x, Integer y) { return x < y.value; }
    public static bool operator >=(Int16 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int16 x, Integer y) { return x <= y.value; }
    public static bool operator >=(Int32 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int32 x, Integer y) { return x <= y.value; }
    public static bool operator >=(Int64 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int64 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt16 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt16 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt32 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt32 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt64 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt64 x, Integer y) { return x <= y.value; }
}
public static class Program
{
    private static bool IntegerFunction(Integer n)
    {
        //code that implements IntegerFunction goes here
        //note that there is NO code that checks the type of n in rum time, because it is NOT needed anymore 
    }
    private static void Main()
    {
        Console.WriteLine("{0}",IntegerFunction(0)); //compile error: there is no overloaded METHOD for objects of type "int" and no implicit conversion from any object, including "int", to "Integer" is known.
        Console.WriteLine("{0}",IntegerFunction(new Integer(0))); //both compiles and no run time error
        Console.WriteLine("{0}",IntegerFunction("string")); //compile error: there is no overloaded METHOD for objects of type "string" and no implicit conversion from any object, including "string", to "Integer" is known.
        Console.WriteLine("{0}",IntegerFunction(new Integer("string"))); //compile error: there is no overloaded CONSTRUCTOR for objects of type "string"
    }
}

Kodunuzda dinamik kullanmak için Microsoft.CSharp'a Başvuru Eklemeniz gerektiğini unutmayın

.NET çerçevesinin sürümü 4.0'ın altında / altında / altındaysa ve dinamik bu sürümde tanımlanmamışsa, bunun yerine nesneyi kullanmanız ve tamsayı türüne döküm yapmanız gerekir, bu da sorun olduğunu, en az .NET 4.0 veya daha yeniyse, nesne yerine dinamik kullanabilirsiniz .


2

Ne yazık ki .NET bunu yerel olarak yapmanın bir yolunu sunmuyor.

Bu sorunu gidermek için, aşağıdaki yerleşik sayısal türler ve nullable eşdeğerleri için diğer sayısal türler için destek ekleme özelliğine sahip en standart sayısal işlemleri sağlayan OSS kütüphanesi Genumerics'i oluşturdum .

sbyte, byte, short, ushort, int, uint, long, ulong, float, double, decimal, VeBigInteger

Performans, verimli genel sayısal algoritmalar oluşturmanıza olanak tanıyan sayısal türe özgü bir çözümle eşdeğerdir.

İşte kod kullanımına bir örnek.

public static T Sum(T[] items)
{
    T sum = Number.Zero<T>();
    foreach (T item in items)
    {
        sum = Number.Add(sum, item);
    }
    return sum;
}
public static T SumAlt(T[] items)
{
    // implicit conversion to Number<T>
    Number<T> sum = Number.Zero<T>();
    foreach (T item in items)
    {
        // operator support
        sum += item;
    }
    // implicit conversion to T
    return sum;
}

1

Egzersizin amacı nedir?

İnsanların zaten işaret ettiği gibi, en büyük öğeyi alan jenerik olmayan bir işleve sahip olabilirsiniz ve derleyici sizin için otomatik olarak daha küçük girişleri dönüştürür.

static bool IntegerFunction(Int64 value) { }

İşleviniz performans açısından kritik bir yoldaysa (çok düşük bir olasılıkla IMO), tüm gerekli işlevler için aşırı yükler sağlayabilirsiniz.

static bool IntegerFunction(Int64 value) { }
...
static bool IntegerFunction(Int16 value) { }

1
Sayısal yöntemlerle çok çalışıyorum. Bazen tamsayılar, bazen kayan nokta istiyorum. Her ikisinin de işlem hızı için en uygun 64 bit sürümleri vardır. Bunlar arasında dönüşüm yapmak her açıdan kayıp olduğu için korkunç bir fikirdir. Çiftleri kullanmaya eğilimliyim, bazen başka yerlerde nasıl kullanıldıklarından dolayı tamsayıları kullanmayı daha iyi buluyorum. Ama bir kez yapmak ve tür kararını örnek gereksinimlerine kadar bırakmak için bir algoritma yazarken çok güzel olurdu.
Oy Verme

1

Ben dışsal ele verebilir genel bir kullanmak istiyorsunuz ...

/// <summary>
/// Generic object copy of the same type
/// </summary>
/// <typeparam name="T">The type of object to copy</typeparam>
/// <param name="ObjectSource">The source object to copy</param>
public T CopyObject<T>(T ObjectSource)
{
    T NewObject = System.Activator.CreateInstance<T>();

    foreach (PropertyInfo p in ObjectSource.GetType().GetProperties())
        NewObject.GetType().GetProperty(p.Name).SetValue(NewObject, p.GetValue(ObjectSource, null), null);

    return NewObject;
}

1

Bu sınırlama, genel türler için işleçleri aşırı yüklemeye çalıştığımda beni etkiledi; "INumeric" kısıtlaması olmadığından ve diğer nedenlerden ötürü yığın akışı üzerindeki iyi insanlara sunmaktan mutluluk duyduklarından, işlemler genel türler üzerinde tanımlanamaz.

Gibi bir şey istedim

public struct Foo<T>
{
    public T Value{ get; private set; }

    public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS)
    {
        return new Foo<T> { Value = LHS.Value + RHS.Value; };
    }
}

Bu sorun, .net4 dinamik çalışma zamanı yazarak kullanarak çalıştım.

public struct Foo<T>
{
    public T Value { get; private set; }

    public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS)
    {
        return new Foo<T> { Value = LHS.Value + (dynamic)RHS.Value };
    }
}

Kullanmayla dynamicilgili iki şey

  1. Verim. Tüm değer türleri kutucuklanır.
  2. Çalışma zamanı hataları. Derleyiciyi "yenersiniz", ancak tip güvenliğini kaybedersiniz. Genel tipte işleç tanımlanmamışsa, yürütme sırasında bir istisna atılır.

1

.NET sayısal ilkel türleri, hesaplamalarda kullanılmasına izin verecek ortak bir arabirimi paylaşmaz. Kendi arayüzler (örneğin tanımlamak mümkün olacağını ISignedWholeNumber) bu tür işlemleri gerçekleştirmek hangi tek ihtiva yapılarını tanımlamak Int16, Int32vb ve bu arabirimleri uygulayan ve ardından kısıtlı jenerik türlerini kabul yöntemleri varISignedWholeNumber , fakat sayısal değerler dönüştürmek zorunda yapı türlerinize büyük olasılıkla bir sıkıntı olacaktır.

Alternatif bir yaklaşım, statik sınıfını tanımlamak olacaktır Int64Converter<T>statik özellik ile bool Available {get;};ve statik delegeleri Int64 GetInt64(T value), T FromInt64(Int64 value), bool TryStoreInt64(Int64 value, ref T dest). Sınıf yapıcısı, bilinen türler için delegeleri yüklemek için sabit kodlanmış olabilir ve muhtemelen türün Työntemleri doğru adlarla ve imzalarla uygulayıp uygulamadığını sınamak için (örneğin Int64, bir sayıyı içeren ve bir sayıyı içeren ancak özel bir ToString()yöntem). Bu yaklaşım, derleme zamanı tür denetlemesiyle ilişkili avantajları kaybeder, ancak yine de boks işlemlerinden kaçınmayı başarır ve her türün yalnızca bir kez "denetlenmesi" gerekir. Bundan sonra, bu türle ilişkili işlemler bir temsilci gönderimi ile değiştirilir.


@KenKin: IConvertible, örneğin bir Int64sonuç elde etmek için herhangi bir tamsayının başka bir tamsayı tipine eklenebileceği bir araç sağlar, ancak örneğin, rastgele tipte bir tamsayının aynı tipte başka bir tamsayıyı vermek üzere arttırılabileceği bir yol sağlamaz .
supercat

1

Ben sayısal türleri ve dizeleri ele gerekiyordu benzer bir durum vardı; biraz tuhaf bir karışım gibi görünüyor ama işte böyle.

Yine, birçok insan gibi, kısıtlamalara baktım ve desteklemesi gereken bir grup arayüz buldum. Bununla birlikte, a)% 100 su geçirmez değildi ve b), bu uzun kısıtlama listesine bakan yeni herkes hemen çok karışık olurdu.

Bu yüzden benim yaklaşımım, tüm mantığımı herhangi bir kısıtlama olmaksızın genel bir yönteme koymak, ancak genel yöntemi özel yapmaktı. Sonra genel yöntemlerle maruz, bir açıkça ele almak istediğim türü işleme - aklımda, kod temiz ve açık, eg

public static string DoSomething(this int input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this decimal input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this double input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this string input, ...) => DoSomethingHelper(input, ...);

private static string DoSomethingHelper<T>(this T input, ....)
{
    // complex logic
}

0

İstediğiniz tek bir sayısal tür kullanmaksa , C ++ ile bir diğer ada benzer bir şey oluşturmayı düşünebilirsiniz using.

Yani çok genel bir

T ComputeSomething<T>(T value1, T value2) where T : INumeric { ... }

sahip olabilirsin

using MyNumType = System.Double;
T ComputeSomething<MyNumType>(MyNumType value1, MyNumType value2) { ... }

Yani kolayca gitmek için izin verebilir doubleetmek intveya başkalarının gerekirse, ama kullanmak mümkün olmaz ComputeSomethingile doubleve intaynı programda.

Ama neden her yerini doublehiç into zaman? Çünkü yönteminiz doublegiriş olsun doubleya da olsun kullanmak isteyebilirsiniz int. Diğer ad, hangi değişkenin dinamik türü kullandığını tam olarak bilmenizi sağlar .


0

Konu eskidir, ancak gelecekteki okuyucular için:

Bu özellik şu Discriminated Unionsana kadar C # 'da uygulanmayan bir özelliktir . Sorununu burada buldum:

https://github.com/dotnet/csharplang/issues/113

Bu sorun hala açık ve özellik için planlandı C# 10

Yine de biraz daha beklemek zorundayız, ancak bıraktıktan sonra bunu şu şekilde yapabilirsiniz:

static bool IntegerFunction<T>(T value) where T : Int16 | Int32 | Int64 | ...

-11

Bence jenerik ilaçları yanlış anlıyorsunuz. Gerçekleştirmeye çalıştığınız işlem yalnızca belirli veri türleri için iyi ise, "genel" bir şey yapmıyorsunuz demektir.

Ayrıca, işlevin yalnızca int veri türleri üzerinde çalışmasına izin vermek istediğiniz için, her bir özel boyut için ayrı bir işleve ihtiyacınız olmamalıdır. En büyük spesifik tipte bir parametre almak, programın daha küçük veri tiplerini otomatik olarak ona göre ayarlamasına izin verecektir. (ör. bir Int16 iletilirse arama sırasında otomatik olarak Int64'e dönüştürülür).

Eğer işleve gerçek int büyüklüğüne göre farklı işlemler yapıyorsanız o zaman ne yaptığınızı yapmaya çalışırken bile ciddi bir şekilde yeniden düşünmek gerektiğini düşünüyorum. Dili kandırmanız gerekiyorsa, istediğiniz şeyi nasıl yapacağınızdan ziyade, neyi başarmaya çalıştığınız hakkında biraz daha düşünmelisiniz.

Her şey başarısız olursa, Object türünde bir parametre kullanılabilir ve ardından parametrenin türünü kontrol etmeniz ve uygun eylemi gerçekleştirmeniz veya bir istisna atamanız gerekir.


10
<T> sınıfı Histogram düşünün. Genel bir parametre almasına izin vermek mantıklıdır, böylece derleyici bunu bayt, ints, çiftler, ondalık, BigInt, ... için optimize edebilir, ancak aynı zamanda bir Histogram <Hashset oluşturmanızı önlemeniz gerekir. >, çünkü - Tron ile konuşmak - hesaplama yapmıyor. (tam anlamıyla :))
sunside

15
Jenerikleri yanlış anlayan sensin. Meta programlama sadece olası herhangi bir tür olabilecek değerler üzerinde değil , çeşitli kısıtlamalara uyan türlerde de kullanılabilir .
Jim Balter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.