How to use a generic parameter type for another generic class?

For me, this seems like a compiler error or some kind of strange behavior. The compiler cannot determine the general type of a parameter in a generic class

the code

public interface IHamster
{
    int Some { get; set; }
}

public abstract class BaseHamster : IHamster
{
    public int Some { get; set; }
}

public class DerivedHamster : BaseHamster
{
}

class ApplyHitHamster<T> where T : IHamster   // <-- same constraint 
{
    void Zu()
    {
        BaseHamster hamster = null;
        var derived = new DerivedHamster();
        IHamster i = derived;

        var s = new TakeDamageHamster<T>(i); // <<<< Compilation Error on any variables(hamster,derived,i) WHY?????????
        var s2 = new TakeDamageHamster<IHamster>(i); // <<<< But THIS works well
    }
}

class TakeDamageHamster<T> where T : IHamster   // <-- same constraint 
{
    public TakeDamageHamster(T Hamster)
    {
        Console.WriteLine(Hamster.Some);
    }
}

How can one be used <T>with the same restriction whereinstead of a direct restriction <IHamster>?

Why can't the compiler determine the type if both classes have the same restriction where T : IHamster?

EDIT: Another simplified example:

public class BaseHamster
{
    public int Some { get; set; }
}

public class DerivedHamster : BaseHamster
{
}

class ApplyHitHamster<T> where T : BaseHamster, new()   // <-- same constraint 
{
    void Zu()
    {
        BaseHamster hamster = new BaseHamster();
        var derived = new DerivedHamster();

        var s = new TakeDamageHamster<T>();
        s.Method(hamster); // <<<< Compilation Error on any variables(hamster,derived) WHY?????????
    }
}

class TakeDamageHamster<T> where T : BaseHamster, new()  // <-- same constraint 
{
    public void Method(T hamster)
    {
        Console.WriteLine(hamster.Some);
    }
}

Another example:

public class BaseHamster
{
    public int Some { get; set; }
}

class ApplyHitHamster<T> where T : BaseHamster, new()   // MSDN: 
{
    void Zu()
    {
        var hamster = new BaseHamster();
        SuperMethod(hamster);  // <<<< WTF? T is ALWAYS BaseHamster!!!
        SuperMethod(hamster as T);    
    }
    void SuperMethod(T x)
    {
    }
}
+4
source share
4 answers

How to make it work?

1. What you can do to make it work is to pass it on T.

BaseHamster hamster = null;
var derived = new DerivedHamster();
T i = derived as T;
var s = new TakeDamageHamster<T>(i);

class.

class ApplyHitHamster<T> where T : class, IHamster
{
    // Other stuff..
}

2. , . .

class TakeDamageHamster<T> where T : IHamster
{
    public TakeDamageHamster(IHamster Hamster)
    {
        Console.WriteLine(Hamster.Some);
    }
}

3. new T(). , new().

BaseHamster hamster = null;
var derived = new T();

var s = new TakeDamageHamster<T>(derived); // <<<< Compilation Error on any variables(hamster,derived,i) WHY?????????
var s2 = new TakeDamageHamster<IHamster>(derived); // <<<< But THIS works well

?

, i T. , AnotherHamster. , BaseHamster, DerivedHamster.

public class DerivedHamster : BaseHamster
{
}

public class AnotherHamster : BaseHamster
{
}

ApplyHitHamster.

var fooHamster = new ApplyHitHamster<AnotherHamster>();
fooHamster.Zu(); // Let pretend that the method is public. :)

, TakeDamageHamster<AnotherHamster>. , DerivedHamster .

BaseHamster hamster = null;
var derived = new DerivedHamster();
IHamster i = derived;
// You cannot send DerivedHamster when it expects AnotherHamster.
var s = new TakeDamageHamster<T>(i); // T is now AnotherHamster.

, i DerivedHamster, TakeDamageHamster<AnotherHamster> a AnotherHamster. .

. , :

var fooHamster = new ApplyHitHamster<BaseHamster>();
fooHamster.Zu();

T BaseHamster. :

var derived = new DerivedHamster();
IHamster i = derived;
var s = new TakeDamageHamster<BaseHamster>(i); // Cannot pass IHamster when ctor expects BaseHamster.

, TakeDamageHamster BaseHamster ( -, ) . IHamster. , BaseHamster IHamster. IHamster BaseHamster.

IHamster, BaseHamster. , IHamster, ? , , constaint .

+6

T , , T IHamster

public TakeDamageHamster(IHamster i)
        {
            // TODO: Complete member initialization
            this.i = i;
        }

IHamster       {           int Some {get; ; }       }

    public abstract class BaseHamster : IHamster
    {
        public int Some { get; set; }
    }

    public class DerivedHamster : BaseHamster
    {
    }

    class ApplyHitHamster<T> where T : IHamster   // <-- same constraint 
    {
        void Zu()
        {
            BaseHamster hamster = null;
            var derived = new DerivedHamster();
            IHamster i = derived;

            var s = new TakeDamageHamster<T>(i); // <<<< Compilation Error on any variables(hamster,derived,i) WHY?????????
            var s2 = new TakeDamageHamster<IHamster>(i); // <<<< But THIS works well
        }
    }

    class TakeDamageHamster<T> where T : IHamster   // <-- same constraint 
    {
        private IHamster i;

        public TakeDamageHamster(T Hamster)
        {
            Console.WriteLine(Hamster.Some);
        }

        public TakeDamageHamster(IHamster i)
        {
            // TODO: Complete member initialization
            this.i = i;
        }
    }
0

.

var s = new TakeDamageHamster<T>(i); 

, , , , T DerivedHamster. T IHamster. .

var s2 = new TakeDamageHamster<DerivedHamster>(derived); 

, .

class ApplyHitHamster<T> where T : IHamster  
{
    void Zu()
    {
        var derived = new DerivedHamster();
        var s2 = new TakeDamageHamster<DerivedHamster>(derived); 
        var s3 = CreateTakeDamageHamster(derived);
    }

    TakeDamageHamster<T2> CreateTakeDamageHamster<T2>(T2 hammie)
        where T2 : IHamster 
    {
        return new TakeDamageHamster<T2>(hammie);
    }
}
0

. , ApplyHitHamster<DerivedHamster>. Zu :

IHamster i = derived;

var s = new TakeDamageHamster<DerivedHamster>(i);

You can clearly see what ctor TakeDamageHamsterrequires DerivedHamster, and you are trying to pass on to it IHamster. He can't work.

if you want yours to Zuwork the way you do, you need to do:

class TakeDamageHamster<T> where T : IHamster   // <-- same constraint 
{
    public TakeDamageHamster(IHamster Hamster)//<-- now this is compatible with constraint alone, no matter what T is.
    {
        Console.WriteLine(Hamster.Some);
    }
}

Now you can create TakeDamageHamsterwith any general parameter you want and initialize it only with the base interface.

0
source

Source: https://habr.com/ru/post/1661595/


All Articles