Pregunta

Mi pregunta se refiere a la c# y cómo acceder a los miembros Estáticos ...Bueno, yo realmente no sé cómo explicarlo (¿qué es malo para una pregunta ¿no?) Me limitaré a dar algunos ejemplo de código:

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()
     }
}

Así que gracias chicos por sus respuestas (Por cierto la pregunta es:¿cómo puedo solucionar este problema sin necesidad de obtener un error).Esto, probablemente, bastante una pregunta fácil para usted!

Gracias, Niklas


Editar:Gracias a todos por sus respuestas!

Aunque creo que el try - catch frase es la más elegante, yo sé de mi experiencia con vb que realmente puede ser una decepción.He utilizado una vez, y que tomó cerca de 30 minutos para ejecutar un programa, que más tarde tomó sólo 2 minutos a calcular sólo porque he evitado try - catch.

Esta es la razón por la que elegí la swich declaración como la mejor respuesta.Que hace el código más complicado, pero por otro lado me imagino que para ser relativamente rápido y relativamente fácil de leer.(Aunque sigo pensando que debe haber una forma más elegante ...tal vez en el siguiente idioma aprendo :P )


Aunque si tienes alguna otra sugerencia todavía estoy esperando (y dispuestos a participar)

¿Fue útil?

Solución

Una forma más de hacerlo, este momento de reflexión en la mezcla:

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;
    }
}

El siguiente paso sería tratar de poner en práctica

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

Con plena parámetro de tipo de coincidencia etc.

Otros consejos

El problema es que TryParse no está definido en una interfaz o clase base en cualquier lugar, así que usted no puede hacer una suposición de que el tipo se pasa en la clase tendrá esa función.A menos que usted puede contrain T de alguna manera, tendremos mucho de esto.

Las restricciones en los Parámetros de Tipo

Respuesta corta, no se puede.

Respuesta larga, puede engañar:

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();
    }
}

He hecho una estática diccionario de la celebración de un delegado por el método TryParse de todo tipo, que me quiera utilizar.Entonces escribí un método genérico para buscar palabras en el diccionario y pasar la llamada al correspondiente delegado.Ya que cada delegado tiene un tipo diferente, acabo de almacenarlos como referencias de objeto y los echarán al correspondiente tipo genérico cuando me recupere de ellos.Tenga en cuenta que por el bien de un simple ejemplo he omitido la comprobación de errores, tales como comprobar si tenemos una entrada en el diccionario para el tipo dado.

Para tener acceso a un miembro de una determinada clase o interfaz que usted necesita para utilizar la palabra clave where y especificar la interfaz o clase base que tiene el método.

En la anterior instancia TryParse no proviene de una interfaz o clase base, así que lo que están tratando de hacer de arriba no es posible.El mejor uso Convertir.ChangeType y un try/catch declaración.

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

¿Te refieres a hacer algo como esto:

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
         }
     }
}

Lamentablemente no se puede comprobar la TryParse patrón, ya que es estática, que lamentablemente significa que no está particularmente bien adaptado para los medicamentos genéricos.

La única manera de hacer exactamente lo que usted está buscando sería el uso de la reflexión para comprobar si existe el método de T.

Otra opción es asegurarse de que el objeto de enviar un convertible objeto de restricción en el tipo de IConvertible (todos los tipos primitivos implementar IConvertible).Esto le permitirá convertir su parámetro para el tipo dado muy flexible.

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

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

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

También puedes hacer una variación de este mediante el uso de un "objeto" del tipo de cambio como el que tenía originalmente.

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 chicos:Gracias por todo el pescado.Ahora, con sus respuestas y mi investigación (especialmente el artículo sobre la limitación genérica de los tipos primitivos) Voy a presentar mi solución.

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();
    }
}

Esta no es realmente una solución, pero en ciertas situaciones podría ser una buena alternativa:Podemos pasar un delegado adicional para el método genérico.

Para aclarar lo que quiero decir, vamos a usar un ejemplo.Digamos que tenemos algunos genérico método de fábrica, que debe crear una instancia de T, y queremos que, a continuación, llamar a otro método, para la notificación o de inicialización adicionales.

Considere el siguiente sencillo de la clase:

public class Example
{
    // ...

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

Y el siguiente método estático:

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

Así que ahora tenemos que hacer:

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

Sin embargo, podemos cambiar nuestro método para tomar un delegado adicional:

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;
}

Y ahora podemos cambiar la llamada a:

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

Obviamente, esto sólo es útil en determinados escenarios.Pero esta es la solución más limpia en el sentido de que tenemos tiempo de compilación de seguridad, no es "hackear" involucrados, y el código es muy sencillo.

Usted probablemente no puedo hacerlo.

Primero de todos, si debe ser posible sería necesario una mayor enlazado en T para la typechecker podía estar seguro de que todas las sustituciones posibles para T en realidad tenía un método estático llamado TryParse.

Es posible que desee leer mi post anterior sobre la limitación genérica de los tipos primitivos.Esto puede dar algunos consejos para limitar el tipo que se puede pasar a la genérica (desde TypeParse es, obviamente, sólo disponible para un número de conjunto de primitivas ( de la cadena.TryParse obviamente, siendo la excepción, que no tiene sentido).

Una vez que usted tiene más de un identificador del tipo, puede trabajar en intentar analizarlo.Usted puede necesitar un poco de un feo interruptor de allí (para llamar la correcta TryParse pero creo que se puede lograr la funcionalidad deseada.

Si me necesitas para explicar cualquier de los de arriba más, entonces por favor, pregunte :)

Mejor código:restringir T a ValueType de esta manera:

class test1<T> where T: struct

Un "struct" aquí significa un tipo de valor.String es una clase, no un tipo de valor.int, float, las Enumeraciones son todos los tipos de valor.

por cierto, el compilador no acepta llamar a métodos estáticos o de acceso a los miembros estáticos en "parámetros de tipo' como en el ejemplo siguiente, que no se compile :(

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

=> Error 1 'T' es un parámetro de tipo', que no es válido en el contexto dado

SL.

Que no es la forma estática de trabajo.Usted tiene que pensar en la estática como en una clase Global, incluso si son se propagan a través de un montón de tipos.Mi recomendación es hacerlo de una propiedad en el interior de la T instancia en la que se puede acceder a la necesaria método estático.

También T es una instancia real de algo, y como cualquier otra instancia que no son capaces de acceder a la estática de ese tipo, a través de las instancias de valor.Aquí es un ejemplo de lo que debe hacer:

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()
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top