C# generics - without lower bounds by design?

后端 未结 3 822
-上瘾入骨i
-上瘾入骨i 2020-12-15 06:30

I was reading an interview with Joshua Bloch in Coders at Work, where he lamented the introduction of generics in Java 5. He doesn\'t like the specific implementation largel

相关标签:
3条回答
  • 2020-12-15 07:11

    C# 4 introduces new features that allow covariance and contravariance in generics.

    There are other SO posts that talk about this in more detail: How is Generic Covariance & Contra-variance Implemented in C# 4.0?

    The new feature does not enable this automatically in all types, but there is a new syntax that allows developers to specify whether generic arguments are covariant or contravariant.

    C# versions prior to C# 4 had limited functionality similar to this as it pertains to delegates and certain array types. With regard to delegates, delegates that take in base parameter types are allowed. With regard to array types, I think it's valid unless there would be boxing involved. That is, an array of Customer can be case to an array of object. However, an array of ints cannot be cast to an array of objects.

    0 讨论(0)
  • 2020-12-15 07:15

    .net already has the equivalent of wildcards, more logically named generic type constraints, you can do what you describe with no problems

    namespace ConsoleApplication3
    {
        class Program
        {
            static void Main(string[] args)
            {
             List<a> a = new List<a>();
             List<b> b = new List<b>();
             List<c> c = new List<c>();
             test(a);
             test(b);
             test(c);
    
            }
    
            static void test<T>(List<T> a) where T : a
            {
                return;
            }
        }
        class a
        {
    
        }
        class b : a
        {
    
        }
        class c : b
        {
    
        }
    }
    

    Example 2

    namespace ConsoleApplication3
    {
        class Program
        {
            static void Main(string[] args)
            {
                ICollection<VanillaOption> src = new List<VanillaOption>();
            ICollection<Derivative> dst = new List<Derivative>();
             copyAssets(src, dst);
            }
    
            public static void copyAssets<T,G>(ICollection<T> src, ICollection<G> dst) where T : G {
                foreach(T asset in src) 
                    dst.Add(asset);
            }
        }
        public class Asset {}
        public class Derivative : Asset {}
        public class VanillaOption : Derivative {}
    }
    

    This example represents a code conversion from your example in java.

    I'm not really in a position to answer the actual question though!

    0 讨论(0)
  • 2020-12-15 07:19

    A complicated question.

    First let's consider your fundamental question, "why is this illegal in C#?"

    class C<T> where T : Mammal {} // legal
    class D<T> where Giraffe : T {} // illegal
    

    That is, a generic type constraint can say "T must be any reference type that could be assigned to a variable of type Mammal", but not "T must be any reference type, a variable of which could be assigned a Giraffe". Why the difference?

    I don't know. That was long before my time on the C# team. The trivial answer is "because the CLR doesn't support it", but the team that designed C# generics was the same team that designed CLR generics, so that's really not much of an explanation.

    My guess would be simply that as always, to be supported a feature has to be designed, implemented, tested, documented and shipped to customers; no one ever did any of those things for this feature, and therefore it is not in the language. I don't see a large, compelling benefit to the proposed feature; complicated features with no compelling benefits tend to be cut around here.

    However, that's a guess. Next time I happen to chat with the guys who worked on generics -- they live in England, so its not like they're just down the hall from me, unfortunately -- I'll ask.

    As for your specific example, I think Paul is correct. You do not need lower bound constraints to make that work in C#. You could say:

    void Copy<T, U>(Collection<T> src, Collection<U> dst) where T : U 
    { 
        foreach(T item in src) dst.Add(item);
    }
    

    That is, put the constraint on T, not on U.

    0 讨论(0)
提交回复
热议问题