Avatar billede repsak Nybegynder
18. oktober 2010 - 10:29 Der er 20 kommentarer

Vil kun tillade en factory at oprettet en instans af min klasse

Hej, jeg ønsker at lave en klasse som kun kan instansieres fra én bestemt klasse (en factory). Hvordan implementerer jeg dette?


Den syntaks som jeg ønsker er noget ala:

class A
{
    [OnlyAllowCallsFrom(typeof(Factory))]
    public A()
    {
    }
}

class B
{
    public B()
    {
        A a = new A(); //an exception is thrown as A's constructor does not accept other than class Factory to call
    }
}

class Factory
{
    public Factory()
    {
        A a = new A(); //it works
    }
}
Avatar billede Syska Mester
18. oktober 2010 - 11:05 #1
Måske noget ala:
http://geekswithblogs.net/opiesblog/archive/2006/06/29/83654.aspx

Du skal nok bruge reflection til at finde ud af hvad metode som kalder din constructor.

Men kan du ikke lave din constructor internal, så er det jo kun kald fra din dll som vist nok kan bruge den, og så er det problem vel løst.

mvh
Avatar billede repsak Nybegynder
18. oktober 2010 - 12:12 #2
Ja, du har ret i at jeg kan bruge StackFrame, men det virker ikke så elegant og genbrugbart.

Internal constructor er en workaround som dog ikke løser problemet. Jeg er interesseret i en mere deklarativ løsning som skitseret. Har overvejet om CodeAccessSecurity kan bruges, men kan ikke umiddelbart løse det på den måde.
Avatar billede Syska Mester
18. oktober 2010 - 12:23 #3
Lav din klasse som en subclass til din factory klasse, så kan du hide din constructor for omverdenen, men dit factory har stadig adgang til den.

mvh.
Avatar billede repsak Nybegynder
18. oktober 2010 - 12:28 #4
Den vil også løse problemet, men det vil skabe en 'er-en' relation som ikke er ønsket.
Avatar billede Syska Mester
18. oktober 2010 - 12:35 #5
Ja, det vil jo så blive en Factory.A class.

Men tror ikke det som sådan umildbart kan laves, og du vil næsten alligevel altid kunne oprette en instance af det via reflection, så tror ikke du får nogen pæn løsning.

Må man spørge hvad grunden er til at du ikke vil lade andre oprette en instance af den?

mvh
Avatar billede repsak Nybegynder
18. oktober 2010 - 12:55 #6
Det er korrekt at reflection kan hacke sig igennem, men det vil jeg ikke forhindre. Hvis man bruger reflection så ved kan at man KAN bryde de oprindelige intensioner.

Idéen med mit spørgsmål er at jeg har en klasse som jeg vil være sikker på kun kan instantieres via en factory. Således har jeg styr på flowet og sikrer at andre udviklere ikke tilgår klassen direkte (i tilfælde af at der en dag skal skiftes implementering eller ændres i factory logikken). Jeg synes selv at en deklarativ løsning er let at læse og let at bruge - men ved ikke hvordan jeg implementerer den.

Det er muligt at jeg ikke kan få en compiletime fejl, men så vil min unittest opdage en runtime exception.

Giver det mening? :)
Avatar billede Syska Mester
18. oktober 2010 - 13:07 #7
Det giver fint mening, men hvis dine klasse alligevel er så tæt koblet, så synes jeg det er en fin måde at lave en subclass. Det virker nemlig ikke til at du bruger IOC eller andre ting.

Men jeg har ikke lige umildbart en elegant løsning på dit problem, men mon ikke der kommer en senere på dagen, som eventuelt har en ide til det.

mvh
Avatar billede repsak Nybegynder
18. oktober 2010 - 13:12 #8
Ovenstående skal netop være med til at sikre meget løs kobling. Dog er mit eksempel forsimplet så det måske virker omvendt.
Avatar billede Syska Mester
18. oktober 2010 - 13:27 #9
Ja, synes det virker lidt sådan, men ja, kan ske at eksemplet er for enkelt.

pt ser det jo også kun ud til at dit factory kun kan oprette en slags ( class A ).

Men som sagt ... jeg er tom for ideer. Men glæder mig til at se hvad der kommer ind af andre forslag.

mvh
Avatar billede arne_v Ekspert
18. oktober 2010 - 16:05 #10
Umiddelbart vil jeg mene at loesningen er:
- public interface
- internal class
- public factory
Avatar billede bvli Praktikant
18. oktober 2010 - 16:31 #11
Jeg havde for et par år siden samme problem. At opdrage ulydige udviklere er svært. Men altså det blev noget med, at lade runtime'n kalde en factory hver eneste gang nogen mente de skulle lave en "x = new y()". Det lyder simpelt, men det blev lidt noget juks - men det virkede på daværende tidspunkt.

Anyway - løsningen ligger et eller andet sted derude:
http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.general/2004-09/1472.html
Avatar billede Pulchra Nybegynder
18. oktober 2010 - 23:07 #12
Denne tråd diskuterer nogenlunde den samme problematik som du prøver at løse.
Der er ingen silver bullet solution, men et par interesse løsningsforslag.

http://bytes.com/topic/c-sharp/answers/459095-making-constructor-visible-only-certain-class

Mvh.
Hallur
Avatar billede repsak Nybegynder
24. oktober 2010 - 08:27 #13
Tak for kommentarer. Jeg kom ikke nærmere mit mål, men tak for input. Fair nok hvis det teknisk set ikke kan lade sig gøre. Hvordan er kotume med points på eksperten?
Avatar billede arne_v Ekspert
24. oktober 2010 - 15:14 #14
Du fordeler point som du nu synes at det giver mening.
Avatar billede repsak Nybegynder
07. november 2010 - 18:45 #15
Jeg fik ikke løst mig problem. Pulchra, jeg fik mest ud af dit indlæg. Læg et svar :)
Avatar billede nielle Nybegynder
07. november 2010 - 19:27 #16
Måske noget i denne stil?

    class A
    {
        public A(Factory f)
        {
            if (f == null && f.GetType() != typeof(Factory))
            {
                throw new Exception("...");
            }
        }
    }

    class B
    {
        public B()
        {
            A a = new A();
        }
    }

    class Factory
    {
        public Factory()
        {
            A a = new A(this);
        }
    }
Avatar billede repsak Nybegynder
08. november 2010 - 16:30 #17
Ja, det er præcis mit formål. Ikke deklarativt som jeg håbede på, men det er sådan noget jeg skal bruge. Hmm, fin idé at tage initializoren med som argument...

Jeg er med på at man kan diskutere mange ting om kobling ved dette spørgsmål, men det er slet ikke formålet.

nielle, læg et svar og del med Pulchra
Avatar billede arne_v Ekspert
08. november 2010 - 16:42 #18
Hvad forhindrer:

class B
    {
        public B()
        {
            A a = new A(new Factory());
        }
    }

?
Avatar billede nielle Nybegynder
08. november 2010 - 18:17 #19
Intet, men det er i hvert fald garanteret at der har været en initialiseret Factory med i spil.

Desuden er det vist ikke væsentligt forskelligt fra denne konstruktion:

    class B
    {
        public B()
        {
            Factory f = new Factory();
            A a = f.CreateA();
        }
    }

Jeg ved ikke lige hvad der er pointen med at man ønsker at sikre at alle A-instanser er genereret af en Factory, så jeg kan ikke sige om det er godt nok eller ej.
Avatar billede johny Nybegynder
22. december 2010 - 20:57 #20
Hvis din Factory er lavet via Singleton pattern, har du så netop løst det ved at kræve den i konstruktøren til A.

Derudover kunne du også løse det ved simpelthen at generere klasserne udelukkende vha. reflection fra din factory og gør alle konstruktører private?
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