Как зайти в Даркнет?!
25th January, 01:11
8
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
899
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
952
0
Очень долго работает Update запрос Oracle
27th January, 09:58
916
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
907
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
942
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1727
0
период по дням
25th October, 10:44
3957
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3722
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4614
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4382
0
Помогите пожалуйста решить задачи
24th November, 23:53
6088
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4352
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4400
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Дженерики в c# и доступ к статическим членам Т
Мой вопрос касается c# и как получить доступ к статическим мемберам ... Ну, я действительно не знаю, как это объяснить (что в некотором роде плохо для вопроса, не так ли?) Я просто дам вам пример кода:
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()
}
}
Так что спасибо вам, ребята, за ваши ответы (кстати, вопрос в том, как бы я решил эту проблему без получения ошибки). Это, наверное, довольно простой вопрос для вас!
Спасибо, Никлас
Edit: спасибо всем за ваши ответы!
Хотя я думаю, что фраза try - catch является самой элегантной, я знаю по своему опыту работы с vb, что это действительно может быть облом. Я использовал его один раз, и мне потребовалось около 30 минут, чтобы запустить программу, которая позже заняла всего 2 минуты для вычисления только потому, что я избегал try - catch.
Вот почему я выбрал утверждение swich в качестве лучшего ответа. Это делает код более сложным, но с другой стороны, я думаю, что он будет относительно быстрым и относительно легким для чтения. (Хотя я все еще думаю, что должен быть более элегантный способ ... может быть, на следующем языке, который я изучаю: P )
Хотя, если у вас есть какое-то другое предложение, я все еще жду (и готов принять участие)
Чтобы получить доступ к члену определенного класса или интерфейса, необходимо использовать ключевое слово Where и указать интерфейс или базовый класс, содержащий этот метод.
В приведенном выше экземпляре TryParse не происходит из интерфейса или базового класса, поэтому то, что вы пытаетесь сделать выше, невозможно. Лучше всего просто использовать Convert.ChangeType и оператор try/catch.
class test<T>
{
T Method(object P)
{
try {
return (T)Convert.ChangeType(P, typeof(T));
} catch(Exception e) {
return null;
}
}
}
Короткий ответ, вы не можете.
Длинный ответ, вы можете обмануть:
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();
}
}
Я сделал статический словарь, содержащий делегат для метода TryParse каждого типа, который я мог бы использовать. Затем я написал универсальный метод для поиска словаря и передачи вызова соответствующему делегату. Поскольку каждый делегат имеет свой тип, я просто сохраняю их как ссылки на объекты и возвращаю их обратно к соответствующему универсальному типу при их извлечении. Обратите внимание, что ради простого примера я опустил проверку ошибок, например, чтобы проверить, есть ли у нас запись в словаре для данного типа.
Еще один способ сделать это, на этот раз некоторое отражение в миксе:
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;
}
}
Следующим шагом будет попытка реализовать
public static TRet CallStaticMethod<TRet>( object obj, string methodName, params object[] args );
С полным соответствием типа параметра etc.
Неужели ты собираешься сделать что-то подобное:
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
}
}
}
К сожалению, вы не можете проверить наличие шаблона TryParse, поскольку он статичен , что, к сожалению, означает, что он не особенно хорошо подходит для универсальных моделей.
Единственный способ сделать именно то, что вы ищете, - это использовать отражение, чтобы проверить, существует ли метод для T.
Другой вариант-убедиться, что объект, который вы отправляете, является конвертируемым объектом, ограничив тип до IConvertible (все примитивные типы реализуют IConvertible). Это позволит вам очень гибко конвертировать ваш параметр в данный тип.
Class test<T>
{
int method1(IConvertible Parameter1){
IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));
T temp = Parameter1.ToType(typeof(T), provider);
}
}
Вы также можете сделать вариацию на эту тему, используя вместо этого тип 'object', как это было изначально.
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
}
}
}
ОК, ребята: спасибо за всю рыбу. Теперь с вашими ответами и моими исследованиями (особенно со статьей об ограничении родовых типов примитивами ) я представлю вам свое решение.
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();
}
}
Это не совсем решение, но в некоторых сценариях это может быть хорошей альтернативой: мы можем передать дополнительный делегат универсальному методу.
Чтобы пояснить, что я имею в виду, давайте возьмем пример. Допустим, у нас есть какой-то универсальный фабричный метод, который должен создать экземпляр T, и мы хотим, чтобы он затем вызвал другой метод для уведомления или дополнительной инициализации.
Рассмотрим следующий простой класс:
public class Example
{
// ...
public static void PostInitCallback(Example example)
{
// Do something with the object...
}
}
И следующий статический метод:
public static T CreateAndInit<T>() where T : new()
{
var t = new T();
// Some initialization code...
return t;
}
Так что прямо сейчас мы должны были бы сделать:
var example = CreateAndInit<Example>();
Example.PostInitCallback(example);
Однако мы могли бы изменить наш метод, чтобы взять дополнительный делегат:
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;
}
А теперь мы можем изменить вызов на:
var example = CreateAndInit<Example>(Example.PostInitCallback);
Очевидно, что это полезно только в очень специфических сценариях. Но это самое чистое решение в том смысле, что мы получаем безопасность во время компиляции, здесь нет "hacking", и код очень прост.
Лучший код: ограничьте T до ValueType таким образом:
class test1<T> where T: struct
A "struct" здесь означает тип значения. String - это класс, а не тип значения. int, float, Enums - это все типы значений.
кстати компилятор не принимает вызов статических методов или доступ к статическим членам на 'type parameters', как в следующем примере, который не будет компилироваться :(
class MyStatic { public static int MyValue=0; }
class Test<T> where T: MyStatic
{
public void TheTest() { T.MyValue++; }
}
=> Ошибка 1 'T' - это 'type parameter', которая недопустима в данном контексте
SL.
Возможно, вы захотите прочитать мой предыдущий пост об ограничении универсальных типов примитивами . Это может дать вам некоторые указания в ограничении типа, который может быть передан универсальному (так как TypeParse , очевидно, доступен только для заданного числа примитивов ( string.TryParse , очевидно, является исключением, что не имеет смысла).
Как только у вас будет больше дескриптора для типа, вы можете работать над попыткой его проанализировать. Вам может понадобиться немного уродливый переключатель там (чтобы вызвать правильный TryParse ), но я думаю, что вы можете достичь желаемой функциональности.
Если вам нужно, чтобы я объяснил что-либо из вышеперечисленного дальше, то, пожалуйста, спросите :)
Это не то, как работает статика. Вы должны думать о статике как о чем-то вроде глобального класса, даже если они распределены по целой куче типов. Моя рекомендация состоит в том, чтобы сделать его свойством внутри экземпляра T, который может получить доступ к необходимому статическому методу.
Кроме того, T-это фактический экземпляр чего-то, и, как и любой другой экземпляр, вы не можете получить доступ к статике для этого типа через созданное значение. Вот пример того, что нужно делать:
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()
}