Avatar billede mr-kill Nybegynder
31. maj 2009 - 22:47 Der er 12 kommentarer og
1 løsning

Genetic - new(), men contructor skal 2 typer og ikke 0 når den bliver kaldt

Hey

Jeg har en genetic metode der ser ud på denne måde:

public static T Get<T>(string id, string owner) where T : class, IHaveOwner
{
    //do stuff
}

I den metode vil jeg gerne oprette et nyt object af typen T. T's constructor skal bruge 2 typer.

Det vil sige at jeg ikke kan gøre det på denne måde

public static T Get<T>(string id, string owner) where T : class, IHaveOwner, new()
{
    return new T();
}

Med new() skal der jo være en contructor der tager 0 typer med.

Hvad er den bedste løsning på mit problem?

Jeg kan vel ikke gøre opmærksom på at der er den samme slags contructor i alle klasser der bruger mit interface 'IHaveOwner' på nogen måde ?
Avatar billede arne_v Ekspert
31. maj 2009 - 23:15 #1
Du kan ikke angive en constructor med argumenter som constraint i C# generics.

Bedste råd er nok en factory.
Avatar billede arne_v Ekspert
31. maj 2009 - 23:39 #2
Eksempel:

using System;

namespace E
{
    public interface IHaveOwner
    {
        string Id { get; set; }
        string Owner { get; set; }
    }
    public class SomeThingOwned : IHaveOwner
    {
        public string Id { get; set; }
        public string Owner { get; set; }
        public SomeThingOwned(string id, string owner)
        {
            this.Id = id;
            this.Owner = owner;
        }
    }
    public interface ICanCreateOwned
    {
        IHaveOwner Create(string id, string owner);
    }
    public class CreateSomethingOwned : ICanCreateOwned
    {
        public IHaveOwner Create(string id, string owner)
        {
            return new SomeThingOwned(id, owner);
        }
    }
    public class Program
    {
        public static IHaveOwner Get<FT>(string id, string owner) where FT : class, ICanCreateOwned, new()
        {
            ICanCreateOwned factory = new FT();
            return factory.Create(id, owner);
        }
        public static void Main(string[] args)
        {
            IHaveOwner o = Get<CreateSomethingOwned>("123", "ABC");
            Console.WriteLine(o.Id + " " + o.Owner+ " " + o.GetType().Name);
            Console.ReadKey();
        }
    }
}
Avatar billede mr-kill Nybegynder
01. juni 2009 - 00:12 #3
Jeg synes det er underligt at et interface ikke kan lave regler for contructors :(

Kom til at tænke på at det også kan løses med Reflection, men det bliver nok for grimt?

Synes dit bud ser ud af meget kode for at løse et lille problem, men kan godt være det er den bedste løsing.
Avatar billede arne_v Ekspert
01. juni 2009 - 00:21 #4
Interfaces kan ikke angive constructor. Og det synes jeg vel egentlig er meget logisk.

Reflection er ikke specielt kønt - det en af grundene til at jeg foreslog factory.
Avatar billede mr-kill Nybegynder
01. juni 2009 - 00:54 #5
Synes ikke det er logisk at interfaces ikke kan have en constructor. Jeg ser interfaces som et slags reglsæt for hvad en klasse SKAL have og så ville det være smart hvis man kunne angive en regl for en format af constructor.

Men der er jo nok en god grund til at man ikke kan, så jeg må jo bare leve med det. ;)

Bruger factory - så smid et svar og så er der point på vej.

Endnu engang tak for dine kloge ord.
Avatar billede windcape Praktikant
01. juni 2009 - 00:57 #6
Hvad med:

    class Program
    {
        public static T Get<T>(string id, string owner)
            where T : IHaveOwner
        {
            return new T() { Id = id, Owner = owner };
        }       

        static void Main(string[] args)
        {
            IHaveOwner o = Get<OwnedItem>("123", "ABC");   
        }
    }
   
    class OwnedItem : IHaveOwner
    {
        public string Id { get; set; }
        public string Owner { get; set; }
    }
   
    interface IHaveOwner
    {
        string Id { get; set; }
        string Owner { get; set; }
    }
Avatar billede windcape Praktikant
01. juni 2009 - 01:05 #7
Hov, var lige et par fejl i. Her er en udgave som virker:

namespace ConsoleApplication9
{
    class Program
    {
        public static T Get<T>(string id, string owner)
            where T : IHaveOwner, new()
        {
            return new T() { Id = id, Owner = owner };
        }     

        static void Main(string[] args)
        {
            IHaveOwner o = Get<OwnedItem>("123", "ABC"); 
           
            Console.WriteLine(o.Id);
            Console.WriteLine(o.Owner);
           
            Console.ReadLine();
        }
    }
 
    class OwnedItem : IHaveOwner
    {
        public string Id { get; set; }
        public string Owner { get; set; }
    }
 
    interface IHaveOwner
    {
        string Id { get; set; }
        string Owner { get; set; }
    }
}
Avatar billede windcape Praktikant
01. juni 2009 - 01:06 #8
Læs mere her, også et eksempel med reflection: http://www.dalun.com/blogs/05.27.2007.htm
Avatar billede mr-kill Nybegynder
01. juni 2009 - 01:10 #9
Problemet er at de ting contructoren sætter er private og de skal gerne forblive på den måde.

Desuden kræver at også at jeg laver en blank constructor og det vil jeg også gerne undgå.

Har styr på reflection, men det vil jeg også gerne undgå.

Ellers tak for dit forsøg :)
Avatar billede windcape Praktikant
01. juni 2009 - 17:43 #10
Du kan altid lave constructor overloads.

Men hvorfor ønsker du at lave immutable objects gennem generics? Det lyder som det underliggende design er forkert på et eller andet plan.
Avatar billede windcape Praktikant
01. juni 2009 - 17:49 #11
Under alle omstændigheder ender du med den løsning arne_v præsenterede, hvis du ikke vil have en parameterløs konstruktor.
Avatar billede mr-kill Nybegynder
03. juni 2009 - 15:40 #12
arne_v >> Vil du ha point, så smid et svar!
Avatar billede arne_v Ekspert
07. juni 2009 - 04:12 #13
kommer her
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester