[C#] Går det att få "static-liknande" kall för icke statisk metod.

Permalänk

[C#] Går det att få "static-liknande" kall för icke statisk metod.

Jag håller på med ett stycke kod där jag skulle vilja kunna definiera metoder i ett interface som jag sedan skulle kunna kalla på på ett "static-liknande" sätt.
Inte nog med detta. Jag skulle även vilja göra interfacet Generic med ett constraint som är en enum (usch vad dåligt förklarat!).

// Så här skulle jag vilja att det ser ut. public interface Kalle<TEnum> where TEnum : enum { TEnum GetEnum(); }; public class Pelle : Kalle<PelleEnum> { enum class PelleEnum { ETT, TVA } Pelle() { } PelleEnum GetEnum() { return PelleEnum.ETT; } }; // Såhär skulle jag vilja använda det. // Jag skulle vilja kunna anropa funktionen GetEnum() hos klassen Pelle som om den vore deklarerad statisk utan att behöva skapa en instance av pelle. void RandomFunction() { if(localPelleEnum == Pelle.GetEnum()) { } }

Man skulle kunna säga att jag önskar få betendet som om det vore tillåtet att göra en static implementation av funktionen deklarerad i interfacet. Finns det något sätt fiffla till det?

Permalänk
Medlem

Har inte kodad på ett tag nu men:

public PelleEnum static GetEnum()
{
return new PelleEnum().ETT;
}

Permalänk
Avstängd

Du kan enbart ha constraint på att det ska vara en struct (Värdetyp).
Och nej en metod definierad på ett interface kan inte vara static av bra anledningar.

Jag skulle titta på Inversion of control om jag vore dig

Visa signatur
Permalänk
Datavetare

Inte helt på det klara med vad du vill göra, men ett av grundkraven verkar vara att anropa en viss icke-statiskt medlemsfunktion utan att först ha en instans av typen. Detta exempel gör detta

Går tyvärr inte att få till A.Foo() då språket kräver att Foo() är statisk för att det ska vara korrekt syntax. Man kan däremot utnyttja att null är en undertyp till alla referenstyper och därför kommer detta kompilera (null as A).Foo() om Foo() är en medlemsfunktion på typen A.

I isolation kommer detta smälla p.g.a. null referens, men här går det att utnyttja att "extension methods" i C# har statisk dispatch (d.v.s. vilken metod som faktiskt anropas beror endast av statisk typ, inte av underliggande objekt och dess faktiska typ). Så om man då gör en "extension method" så går det att göra (null as A).StaticFoo() där StaticFoo() är en "extension method" som skapar en temporär instans av A och anropar Foo().

using System; using System.Reflection; namespace StaticPolymorfism { public class A { public void Foo() { Console.WriteLine("In A::Foo"); } } public class B { public void Foo() { Console.WriteLine("In B::Foo"); } } public static class Extension { public static void StaticFoo<T>(this T @this) where T : class, new() { MethodInfo foo = typeof(T).GetMethod("Foo"); foo.Invoke(new T(), null); } } class Program { static void Main(string[] args) { (null as A).StaticFoo(); (null as B).StaticFoo(); } } }

Edit: för att förtydliga, detta

void RandomFunction() { if(localPelleEnum == Pelle.GetEnum()) { } }

blir då

void RandomFunction() { if(localPelleEnum == (null as Pelle).StaticGetEnum()) { } }

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem

Det känns som att du bör fundera över liskov substitution principle med vad du vill uppnå.
Om jag inte missförstår mig å det grövsta så borde du kunna använda någon form av type-safe enum pattern.

Visa signatur

"This is VAR, spelled A-U-T-O"

Permalänk

Hehe det verkar som jag var ännu otydligare än vad jag trodde. Det finns egentligen flera saker jag ville uppnå vilket inte riktigt verkade möjligt.

1. Jag ville egentligen tvinga den som implementerar interfacet till att skapa en enum med ett visst namn i sin implementation men detta var, om jag förstod det rätt inte möjligt. Jag upptäckte också att det inte gick att ha enum som constraint vilket var lite drygt.

2. Jag ville att det i interfacet skulle finns en statisk metod som kunde ge mig vilket enum-värde som skulle användas som default. Men att deklarera statiska metoder i ett interface går ju som sagt inte. Det kanske finns eleganta sätt att göra det på men jag hittade inte direkt något.

Från vad jag har sett så tror jag att Yoshmans svar löser en del a mina problem. Jag skrev nämligen en egen hjälpfunktion för att komma runt mitt problem men jag tyckte att den blev ful och tyckte att det kändes dumt att man var tvungen att veta så mycket om objektet och att man var tvungen att allokera objektet innan man kunde kalla på funktionen.

static TEnum GetEnum<TType, TEnum>() : where TType : Kalle<TEnum>, new , where TEnum : enum // i.e. struct, ICompareable ... osv { return new TType.GetEnum(); }

Tack för hjälpen allesammans.

Permalänk
Avstängd

Vad försöker du lösa? Kanske finns en elegantare lösning

Visa signatur
Permalänk

Jag vill göra en UserControl som skall användas till att skapa värden. Denna dialog kommer att se typ likadan ut för en mängd olika typer. Så jag vill göra den generic.

I dialogen kommer det finnas.
- Groupbox
- Combobox(DropDownList)
- Label
- TextBox
- Tooltip

Comboxen skall innehålla enum-värden. Dessa enum-värden skall komma från den klass som man har som argument till genericen. Enumen skall ha samma namn hos alla klasser som man använder som argument till genericen. Vilket gör att man skulle vilja definiera ett interface som tvingar implementatören att implementera en enum med ett visst namn. Comboboxen skall starta på ett visst värde så det interfacet jag talade om tidigare måste också ha en funktion som talar om vilket standard(default) värdet för enumen är. Implementationen för denna funktion kommer ju att se likadan ut hos alla klasser som implementerar interfacet d.v.s:

public class MyClass : MyInterface { enum MyEnum { ett, tva, tre } MyEnum GetDefault() { return MyEnum.ett; } };

Så tyckte jag att det borde vara möjligt att göra funktionen statisk så att jag slipper allokera ett objekt bara för att kalla på funktionen.
Eftersom man sedan vill kunna skriva tillbaka värdet till dialogen eftersom man vill kunna ändra på värdet beroende på vilket värde som man väljer i comboboxen så måste det finnas en ToString funktion som tar enum-värde som argument(och kanske också en CultureInfo).

Så som den naiva programmera jag är så trodde jag att det "bara" skulle gå och göra följande.

public interface IMyUserControl { enum MyEnum; // Now every implementor needs to have this enum. static MyEnum GetDefault(); // Every implementation needs to have a way to get the default value for the enum. string ToString(MyEnum enum, CultureInfo cultureInfo); // a tostring method. }; public partial class MyUserControl<TType> : UserControl { public MyUserControl() { InitializeComponent(); } } partial class MyUserControl<TType> where TType : IMyUserControl { private void InitializeComponent() { this.myGroupBox = new GroupBox(); this.myTextBox = new TextBox(); this.myComboBox = new ComboBox(); this.myLabel = new Label(); this.myToolTip = new ToolTip(); this.myGroupBox.Controls.Add(this.myComboBox); this.myGroupBox.Controls.Add(this.myTextBox); this.myGroupBox.Controls.Add(this.myLabel); //bla bla bl foreach(var value in Enum.GetValues(typeof(TType.MyEnum))) {this.myComboBox.Items.Add(value);} this.myComboBox.SelectedItem = TType.GetDefault(); } private myGroupBox; private myTextBox; private myComboBox; private myLabel; private myToolTip; } void main() { MyDialog<MyClass> myDialog = new MyDialog<MyClass>(); }

Jag vet att det finns en rad saker som inte går att uppnå riktigt. Men det var något i stil med detta som jag försökte åstadkomma.