Declare method using T and where [Answered]

BObig OOF10/5/2022
This is some code from a reddit post i saw and there are some thing i dont understand.

This is the method:
public static T CreateStudentFromEntity<T>(Student entity) where T : IStudent
        {
            var student = Activator.CreateInstance<T>();

            student.Id = entity.Id;
            student.FirstName = entity.Name;
            student.Surname = entity.Surname;
            student.DateOfBirth = DateTime.Parse(entity.DateOfBirth);
            student.Sex = (Sex)entity.Sex;
            student.Address = CreateAddressFromEntity(entity.Address);

            return student;
        }

This is the interface that the method uses:
public interface IStudent
{
    long Id { get; set; }
    string? FirstName { get; set; }
    string? Surname { get; set; }
    DateTime DateOfBirth { get; set; }
    Sex Sex { get; set; }
    string? TelephoneNumber { get; set; }
    Address? Address { get; set; }
}

From what i understand, T is used to be able to make the method more "flixble", not restricting it to a specific return type.

But when adding "where T : IStudent" - it restricts it to only return a object that inherits the IStudent interface?

Could you not just replace T with IStudent and skip the where?

Plase let me know if i got in wrong 🙂

Thanks in advance!
KKouhai10/5/2022
using a constraint like this is
1 - faster
2 - allows you to have concrete return type
KKouhai10/5/2022
Let's say you have an implementation of IStudent like this
public class InternationalStudent : IStudent
{
    long Id { get; set; }
    string? FirstName { get; set; }
    string? Surname { get; set; }
    DateTime DateOfBirth { get; set; }
    string PlaceOfBirth {get; set;}
    Sex Sex { get; set; }
    string? TelephoneNumber { get; set; }
    Address? Address { get; set; }
}

the returned value from CreateStudentFromEntity<InternationalStudent>(entity) would be of InternationalStudent and you can access PlaceOfBirth without casting
PPobiega10/5/2022
Very well explained. This is because of how generics work behind the scenes - the compiler will look at the different types you pass in and actually make a "copy" of the method that works with that specific type.
Ttebeco10/5/2022
- public static T CreateStudentFromEntity<T>(Student entity) where T : IStudent
+ public static T CreateStudentFromEntity<T>(Student entity) where T : IStudent, new()
  {
-     var student = Activator.CreateInstance<T>();
+     var student = new T();
BObig OOF10/5/2022
Okey, thank you for the answer! Just to get my head around it - Could you say that the use of T in this case is to make a method avalible using multiple classes? And the where to restrict it to specific classes?
KKouhai10/5/2022
Yes, where here is used to restrict T to IStudent implementers.
In the first place, you can't instantiate an interface, so you have to use a class.
KKouhai10/5/2022
If you take a look at the code ToBeClone provided, they added another constraint new() this ensures that the caller has passed a class/struct implementing IStudent
Ttebeco10/5/2022
it make sure there's a public parameter less ctor
Ttebeco10/5/2022
meaning you can just new just like you call new everyday
Ttebeco10/5/2022
and you get rid of Activator
Ttebeco10/5/2022
and you still benefits from possible code optimization ... assuming there's any
Ttebeco10/5/2022
using Activator.CreateInstance like you did is a hack and should be avoided
Ttebeco10/5/2022
generics constraint are designed to avoid that as you can see
Ttebeco10/5/2022
i love the attempt at translating french to english in the naming 😄
Ttebeco10/5/2022
string? TelephoneNumber { get; set; }
Ttebeco10/5/2022
Phone
Ttebeco10/5/2022
or PhoneNumber
BObig OOF10/5/2022
Okok! Antother question regarding new(), i would like to say that:
where T : IStudent, new() 

requires a class that implements IStudent interface and new() interface - but new() isnt an interface. Is it instead - it require a the caller to pass an object that can be instantiated? 🙂
BObig OOF10/5/2022
Sorry if im asking the same questions over and over, a bit new to this :p
Ttebeco10/5/2022
public static T CreateStudentFromEntity<T>(Student entity) where T : IStudent, new()
{ ... }

public class A
{
  public A(string s)
}

CreateStudentFromEntity<A>() <=== BUILD ERROR
Ttebeco10/5/2022
it will fail the build telling you that the type A does not contain a parameterless ctor
Ttebeco10/5/2022
because the only ctor for A require a string
BObig OOF10/5/2022
Okey! So new() set the restriction to only accept an object that includes a parameterless contructor? 🙂
KKouhai10/5/2022
Yes, it accepts a type that has a parameterless constructor
Ttebeco10/5/2022
So new() set the restriction
"new()" is a generic constraint, yes (edited / i read too fast)
Ttebeco10/5/2022
void Foo(int bar){}
Foo("abc");
Ttebeco10/5/2022
"bar must be an int"
Ttebeco10/5/2022
this is a constraint
KKouhai10/5/2022
they didn't say redirections, they said restriction 😅
Ttebeco10/5/2022
aaaaaaaaaaaaaaaaaaa
Ttebeco10/5/2022
my bad seriously
Ttebeco10/5/2022
sorry
Ttebeco10/5/2022
yeah "generic constraint" is the term, you're right
Ttebeco10/5/2022
please forgive me, i read too fast
BObig OOF10/5/2022
Haha no worries!
BObig OOF10/5/2022
Thank you guys for the great help, really appriciated 🙂
AAccord10/5/2022
✅ This post has been marked as answered!