Vra

My vraag betref c# en hoe om toegang te verkry Statiese lede ...Wel, ek weet nie regtig hoe om dit te verduidelik (daaronder soort is sleg vir'n vraag is dit nie?) Ek sal net gee jou'n voorbeeld van die kode:

Class test<T>{
     int method1(Obj Parameter1){
         //in here I want to do something which I would explain as
         T.TryParse(Parameter1);

         //my problem is that it does not work ... I get an error.
         //just to explain: if I declare test<int> (with type Integer)
         //I want my sample code to call int.TryParse(). If it were String
         //it should have been String.TryParse()
     }
}

So dankie julle ouens vir jou antwoorde (Deur die manier waarop die vraag is:hoe sou ek hierdie probleem op te los sonder om'n fout).Dit is waarskynlik nogal'n maklike vraag vir jou!

Dankie, Niklas


Edit:Baie dankie aan almal vir jou antwoorde!

Al het ek dink die probeer - catch frase is die mees elegante, ek weet uit my ervaring met vb dat dit kan regtig'n bummer.Ek gebruik dit een keer en dit het ongeveer 30 minute'n program uit te voer, wat later op het net 2 minute om te bereken net omdat ek vermy probeer om - vang.

Dit is die rede waarom ek besluit het om die swich verklaring as die beste antwoord.Dit maak die kode meer ingewikkeld, maar aan die ander kant ek dink dit is redelik vinnig en relatief maklik om te lees.(Alhoewel ek nog steeds dink daar moet'n meer elegante manier ...miskien in die volgende taal wat ek leer :P )


Maar as jy het'n paar ander voorstel ek is nog steeds wag (en bereid is om deel te neem)

Was dit nuttig?

Oplossing

Nog 'n manier om dit te doen, dié keer 'n weerspieëling in die mengsel:

static class Parser
{
    public static bool TryParse<TType>( string str, out TType x )
    {
        // Get the type on that TryParse shall be called
        Type objType = typeof( TType );

        // Enumerate the methods of TType
        foreach( MethodInfo mi in objType.GetMethods() )
        {
            if( mi.Name == "TryParse" )
            {
                // We found a TryParse method, check for the 2-parameter-signature
                ParameterInfo[] pi = mi.GetParameters();
                if( pi.Length == 2 ) // Find TryParse( String, TType )
                {
                    // Build a parameter list for the call
                    object[] paramList = new object[2] { str, default( TType ) };

                    // Invoke the static method
                    object ret = objType.InvokeMember( "TryParse", BindingFlags.InvokeMethod, null, null, paramList );

                    // Get the output value from the parameter list
                    x = (TType)paramList[1];
                    return (bool)ret;
                }
            }
        }

        // Maybe we should throw an exception here, because we were unable to find the TryParse
        // method; this is not just a unable-to-parse error.

        x = default( TType );
        return false;
    }
}

Die volgende stap sou wees om te probeer implementeer

public static TRet CallStaticMethod<TRet>( object obj, string methodName, params object[] args );

Met volle parameter tipe passing ens.

Ander wenke

Die probleem is dat TryParse nie gedefinieer op 'n koppelvlak of basis klas oral, sodat jy 'n aanname dat die tipe geslaag in jou klas wat funksie sal hê nie kan maak. Tensy jy T kan CONT in een of ander manier, sal jy loop in hierdie baie.

Beperkings op Tipe Parameters

Kort antwoord, kan jy nie.

Long antwoord, kan jy oneerlik:

public class Example
{
    internal static class Support
    {
        private delegate bool GenericParser<T>(string s, out T o);
        private static Dictionary<Type, object> parsers =
            MakeStandardParsers();
        private static Dictionary<Type, object> MakeStandardParsers()
        {
            Dictionary<Type, object> d = new Dictionary<Type, object>();
            // You need to add an entry for every type you want to cope with.
            d[typeof(int)] = new GenericParser<int>(int.TryParse);
            d[typeof(long)] = new GenericParser<long>(long.TryParse);
            d[typeof(float)] = new GenericParser<float>(float.TryParse);
            return d;
        }
        public static bool TryParse<T>(string s, out T result)
        {
            return ((GenericParser<T>)parsers[typeof(T)])(s, out result);
        }
    }
    public class Test<T>
    {
        public static T method1(string s)
        {
            T value;
            bool success = Support.TryParse(s, out value);
            return value;
        }
    }
    public static void Main()
    {
        Console.WriteLine(Test<int>.method1("23"));
        Console.WriteLine(Test<float>.method1("23.4"));
        Console.WriteLine(Test<long>.method1("99999999999999"));
        Console.ReadLine();
    }
}

Ek het 'n statiese woordeboek hou 'n afgevaardigde vir die TryParse metode van elke tipe ek dalk wil gebruik. Ek het toe geskryf 'n generiese metode om op te kyk die woordeboek en slaag op die oproep om die toepaslike afgevaardigde. Aangesien elke afgevaardigde het 'n ander soort, ek slaan hulle net so voorwerp verwysings en gooi dit terug na die toepaslike generiese tipe toe ek hulle gaan haal. Let daarop dat ter wille van 'n eenvoudige voorbeeld Ek het foutopsporing weggelaat, soos om te kyk of ons 'n inskrywing in die woordeboek vir die gegewe tipe.

Om toegang tot 'n lid van 'n spesifieke klas of koppelvlak wat jy nodig het om die Waar navraag gebruik en spesifiseer die koppelvlak of basis klas wat die metode het.

In die bogenoemde geval TryParse kom nie van 'n koppelvlak of basis klas, so wat jy probeer om bo te doen, is nie moontlik nie. Beste net gebruik Convert.ChangeType en 'n drie / vangs verklaring gesê.

class test<T>
{
    T Method(object P)
    {
       try {
           return (T)Convert.ChangeType(P, typeof(T));
       } catch(Exception e) {
           return null;
       }
    }
}

Bedoel jy om iets te doen:

Class test<T>
{
     T method1(object Parameter1){

         if( Parameter1 is T ) 
         {
              T value = (T) Parameter1;
             //do something with value
             return value;
         }
         else
         {
             //Parameter1 is not a T
             return default(T); //or throw exception
         }
     }
}

Ongelukkig kan jy nie kyk vir die TryParse patroon as dit is staties -. Wat ongelukkig beteken dat dit nie besonder goed geskik is vir generiese

Die enigste manier om dit te doen presies wat jy op soek is vir jou sal wees om te gebruik refleksie om te kyk of die metode bestaan vir T.

Nog'n opsie is om te verseker dat die voorwerp wat jy stuur in'n omskepbare voorwerp deur die matigende van die tipe om te IConvertible (al primitiewe tipes implementeer IConvertible).Dit sal toelaat dat jy om te sit jou parameter om die gegewe tipe baie buigsaam.

Class test<T>
{
    int method1(IConvertible Parameter1){

        IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));

        T temp = Parameter1.ToType(typeof(T), provider);
    }
}

Jy kan ook'n variasie op hierdie deur gebruik te maak van'n "voorwerp" tipe in plaas soos jy het oorspronklik.

Class test<T>
{
    int method1(object Parameter1){

        if(Parameter1 is IConvertible) {

            IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));

            T temp = Parameter1.ToType(typeof(T), provider);

        } else {
           // Do something else
        }
    }
}

Ok ouens: Dankie vir al die vis. Nou met jou antwoorde en my navorsing (veral die artikel oor beperking van generiese tipes te primitiewes ) Ek sal jou my oplossing.

Class a<T>{
    private void checkWetherTypeIsOK()
    {
        if (T is int || T is float //|| ... any other types you want to be allowed){
            return true;
        }
        else {
            throw new exception();
        }
    }
    public static a(){
        ccheckWetherTypeIsOK();
    }
}

Dit is nie regtig 'n oplossing, maar in sekere scenario's kan dit 'n goeie alternatief wees: Ons kan 'n bykomende afgevaardigde slaag om die generiese metode

.

Om te verduidelik wat ek bedoel, kom ons gebruik 'n voorbeeld. Kom ons sê ons het 'n paar generiese fabriek metode, moet dit 'n geval van T skep, en ons wil hê dit moet dan bel 'n ander metode, vir kennisgewing of bykomende inisialisering.

Oorweeg die volgende eenvoudige klas:

public class Example
{
    // ...

    public static void PostInitCallback(Example example)
    {
        // Do something with the object...
    }
}

En die volgende statiese metode:

public static T CreateAndInit<T>() where T : new()
{
    var t = new T();
    // Some initialization code...
    return t;
}

So nou het ons sal moet doen:

var example = CreateAndInit<Example>();
Example.PostInitCallback(example);

Maar, kan ons ons metode te verander na 'n bykomende afgevaardigde neem:

public delegate void PostInitCallback<T>(T t);
public static T CreateAndInit<T>(PostInitCallback<T> callback) where T : new()
{
    var t = new T();
    // Some initialization code...
    callback(t);
    return t;
}

En nou kan ons die oproep verander na:

var example = CreateAndInit<Example>(Example.PostInitCallback);

Dit is duidelik dat hierdie is net nuttig in baie spesifieke scenario. Maar dit is die skoonste oplossing in die sin dat ons saam te stel tyd veiligheid, daar is geen "inbraak" betrokke is, en die kode is dood eenvoudig.

Jy het waarskynlik cant dit doen.

In die eerste plek is dit moontlik moet wees wat jy sal 'n strenger gebind op T moet so die typechecker kan seker wees dat alle moontlike vervangings vir T eintlik 'n statiese metode genoem TryParse.

Jy mag wil my vorige post op beperking van generiese tipes te primitiewes lees. Dit kan jy 'n paar wenke gee in die beperking van die tipe wat kan oorgedra word na die generiese (sedert TypeParse is natuurlik slegs beskikbaar vir 'n sekere aantal van primitiewe ( string.TryParse natuurlik dat die uitsondering, wat nie sin maak nie).

As jy meer van 'n handvatsel op die tipe, jy kan dan werk op probeer om dit te ontleed. Jy kan 'n bietjie van 'n lelike skakelaar moet in daar (na die korrekte bel TryParse ), maar ek dink jy kan die gewenste funksie te bereik.

As jy my nodig het om enige van die bogenoemde verder verduidelik, dan moet jy vra:)

Beste kode: beperk T om op hierdie manier Waarde Type:

class test1<T> where T: struct

'n "struct" beteken hier 'n waarde tipe. String is 'n klas, nie 'n waarde tipe. int, float, Enums is alle vorme waarde.

btw die samesteller nie aanvaar om statiese metodes of toegang statiese lede op 'n tipe parameters 'n beroep soos in die volgende voorbeeld wat nie saam te stel: (

class MyStatic { public static int MyValue=0; }
class Test<T> where T: MyStatic
{
    public void TheTest() { T.MyValue++; }
}

=> Fout 1 "T" is 'n "tipe parameter ', wat nie geldig is in die gegewe konteks

SL.

Dit is nie hoe statika werk. Jy het in 'n Global klas om te dink van statika as 'n soort van selfs as hulle is versprei oor 'n hele klomp van die tipes. My aanbeveling is om dit te maak 'n eiendom binne die T byvoorbeeld dat toegang tot die nodige statiese metode.

Ook T is 'n werklike geval van iets, en net soos enige ander instansie wat jy is nie in staat om toegang te verkry tot die statika vir daardie tipe, deur die aangehaal waarde. Hier is 'n voorbeeld van wat om te doen:

class a {
    static StaticMethod1 ()
    virtual Method1 ()
}

class b : a {
    override Method1 () return StaticMethod1()
}

class c : a {
    override Method1 () return "XYZ"
}

class generic<T> 
    where T : a {
    void DoSomething () T.Method1()
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top