Я протестировал его так, и он сработал:
SET /P Var= | Cmd
Путем передачи команды в переменную приглашение вставляет результат команды «Cmd
» в переменную «Var
".
Обновление:
Это не работает, мой плохой, сценарий, который я сделал, был следующим:
SET /P Var= | dir /b *.txt
echo %Var%
Это на самом деле показывало, скажем, «test.txt
», но на самом деле он показывал результат команды «dir /b *.txt
», а не echo %var%
. Я запутался, так как оба выхода были одинаковыми.
Вы должны использовать класс TypeDescriptor :
public static T Convert<T>(this string input)
{
try
{
var converter = TypeDescriptor.GetConverter(typeof(T));
if(converter != null)
{
// Cast ConvertFromString(string text) : object to (T)
return (T)converter.ConvertFromString(input);
}
return default(T);
}
catch (NotSupportedException)
{
return default(T);
}
}
Используя информацию выше, это то, что я разработал. Это позволит преобразовать объект напрямую, в противном случае он преобразует объект в строку и вызовет метод TryParse для нужного типа объекта.
Я кэширую методы в словаре, так как каждый встречается, чтобы уменьшить нагрузку при извлечении метода.
Можно проверить, можно ли напрямую преобразовать объект в целевой тип, что еще больше уменьшит часть преобразования строк. Но я оставлю это пока.
/// <summary>
/// Used to store TryParse converter methods
/// </summary>
private static readonly Dictionary<Type, MethodInfo> TypeConverters = new Dictionary<Type, MethodInfo>();
/// <summary>
/// Attempt to parse the input object to the output type
/// </summary>
/// <typeparam name="T">output type</typeparam>
/// <param name="obj">input object</param>
/// <param name="result">output result on success, default(T) on failure</param>
/// <returns>Success</returns>
public static bool TryParse<T>([CanBeNull] object obj, out T result)
{
result = default(T);
try
{
switch (obj)
{
// don't waste time on null objects
case null: return false;
// if the object is already of type T, just return the value
case T val:
result = val;
return true;
}
// convert the object into type T via string conversion
var input = ((obj as string) ?? obj.ToString()).Trim();
if (string.IsNullOrEmpty(input)) return false;
var type = typeof (T);
Debug.WriteLine($"Info: {nameof(TryParse)}<{type.Name}>({obj.GetType().Name}=\"{input}\")");
if (! TypeConverters.TryGetValue(type, out var method))
{
// get the TryParse method for this type
method = type.GetMethod("TryParse",
new[]
{
typeof (string),
Type.GetType($"{type.FullName}&")
});
if (method is null)
Debug.WriteLine($"FAILED: Cannot get method for {type.Name}.TryParse()");
// store it so we don't have to do this again
TypeConverters.Add(type, method);
}
// have to keep a reference to parameters if you want to get the returned ref value
var parameters = new object[] {input, null};
if ((bool?) method?.Invoke(null, parameters) == true)
{
result = (T) parameters[1];
return true;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
return false;
}
я не вижу преимущества в наличии такого дженерика TryParse
функция. Существует слишком много различных стратегий парсинга и преобразования данных между различными типами с возможным конфликтующим поведением. Как эта функция могла знать который стратегия выбрать контекстно-свободным способом?
Convert.ChangeType
. Этот API настраиваем во времени выполнения. Ваша функция требует поведения по умолчанию или допускает настройку? Я поместил набор идей здесь вместе и закончил с очень коротким решением.
Это - дополнительный метод на строке
enter code here
, я сделал его с тем же следом как методы TryParse на числовых типах
/// <summary>
/// string.TryParse()
///
/// This generic extension method will take a string
/// make sure it is not null or empty
/// make sure it represents some type of number e.g. "123" not "abc"
/// It then calls the appropriate converter for the type of T
/// </summary>
/// <typeparam name="T">The type of the desired retrunValue e.g. int, float, byte, decimal...</typeparam>
/// <param name="targetText">The text to be converted</param>
/// <param name="returnValue">a populated value of the type T or the default(T) value which is likely to be 0</param>
/// <returns>true if the string was successfully parsed and converted otherwise false</returns>
/// <example>
/// float testValue = 0;
/// if ( "1234".TryParse<float>( out testValue ) )
/// {
/// doSomethingGood();
/// }
/// else
/// {
/// handleTheBadness();
/// }
/// </example>
public static bool TryParse<T>(this string targetText, out T returnValue )
{
bool returnStatus = false;
returnValue = default(T);
//
// make sure the string is not null or empty and likely a number...
// call whatever you like here or just leave it out - I would
// at least make sure the string was not null or empty
//
if ( ValidatedInputAnyWayYouLike(targetText) )
{
//
// try to catch anything that blows up in the conversion process...
//
try
{
var type = typeof(T);
var converter = TypeDescriptor.GetConverter(type);
if (converter != null && converter.IsValid(targetText))
{
returnValue = (T)converter.ConvertFromString(targetText);
returnStatus = true;
}
}
catch
{
// just swallow the exception and return the default values for failure
}
}
return (returnStatus);
}
'' '
Как вы сказали, TryParse
не является частью интерфейса. Он также не является членом какого-либо базового класса, поскольку на самом деле статические
и статические
функции не могут быть виртуальными
. Итак, компилятор не может гарантировать, что T
действительно имеет член с именем TryParse
, поэтому это не сработает.
Как сказал @Mark, вы можете создать свой собственный интерфейс и использовать пользовательские типы, но вам не повезло со встроенными типами.
Это вопрос «общих ограничений». Поскольку у вас нет определенного интерфейса, вы застряли, если не последуете предложениям предыдущего ответа.
Для документации по этому поводу проверьте следующую ссылку:
http://msdn.microsoft.com/en-us/library/ms379564 (VS.80) .aspx
Здесь показано, как использовать эти ограничения и должны дать вам еще несколько подсказок.
Когда я хотел сделать почти то же самое, мне приходилось реализовывать это на собственном горьком опыте, учитывая размышления. Учитывая T
, подумайте о typeof (T)
и найдите метод TryParse
или Parse
, вызывая его, если вы его нашли. .
Как насчет этого?
http://madskristensen.net/post/Universal-data-type-checker.aspx ( Архив )
/// <summary>
/// Checks the specified value to see if it can be
/// converted into the specified type.
/// <remarks>
/// The method supports all the primitive types of the CLR
/// such as int, boolean, double, guid etc. as well as other
/// simple types like Color and Unit and custom enum types.
/// </remarks>
/// </summary>
/// <param name="value">The value to check.</param>
/// <param name="type">The type that the value will be checked against.</param>
/// <returns>True if the value can convert to the given type, otherwise false. </returns>
public static bool CanConvert(string value, Type type)
{
if (string.IsNullOrEmpty(value) || type == null) return false;
System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(type);
if (conv.CanConvertFrom(typeof(string)))
{
try
{
conv.ConvertFrom(value);
return true;
}
catch
{
}
}
return false;
}
Это может быть легко преобразован в общий метод.
public static bool Is<T>(this string value)
{
if (string.IsNullOrEmpty(value)) return false;
var conv = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
if (conv.CanConvertFrom(typeof(string)))
{
try
{
conv.ConvertFrom(value);
return true;
}
catch
{
}
}
return false;
}
Вы не можете сделать это для общих типов.
Что вы можете сделать, так это создать интерфейс ITryParsable и использовать его для пользовательских типов, которые реализуют этот интерфейс.
Однако я предполагаю, что вы собираетесь использовать его для базовых типов, таких как int
и DateTime
. Вы не можете изменить эти типы для реализации новых интерфейсов.
Если вы настроены на использование TryParse, вы можете использовать отражение и сделать это следующим образом:
public static bool Is<T>(this string input)
{
var type = typeof (T);
var temp = default(T);
var method = type.GetMethod(
"TryParse",
new[]
{
typeof (string),
Type.GetType(string.Format("{0}&", type.FullName))
});
return (bool) method.Invoke(null, new object[] {input, temp});
}