То, что я делаю, ищет значение для конкретного поля в хеш-таблице. Объект может быть горсткой типов примитивов, кто значение, предназначен, чтобы быть вставленным XML, но это выходит из хеш-таблицы как из объекта. Таким образом, у меня есть проблема необходимости решить, каков тип, выбросил ее и затем использует, который вводит ToString. Было бы хорошо, если бы я не должен был бросать его, но затем это назовет ToString на типе объекта а не методе дубликата на фактическом типе.
Следующий код является функционально правильным, но я не доволен им. Возможно, после этого комфорта путь приведет ко мне являющийся пуристом. Так или иначе я был бы очень признателен за более хороший способ записать это, если такой существует.
public string GetColumnValue(string columnName)
{
object value = item[columnName];
if (value == null)
return string.Empty;
if (value.GetType() == typeof(string))
{
return (string)value;
}
else if (value.GetType() == typeof(double))
{
return ((double)value).ToString();
}
...
}
Разрешение таймеров в Windows ограничено примерно 10 миллисекундами, поэтому вы никогда не сможете получить значения времени с точностью до микросекунд.
Если ваши значения времени поступают из другого места, которое способно к такому разрешению, тогда возьмите эти значения за микросекунды. Умножение на 1000 или деление int на 1000 не даст вам лучшего разрешения, это просто изменит масштаб вашего сравнения.
-121--1948992-Я думаю, что лучшим решением было бы сделать метод A виртуальным, а не иметь B-повторную реализацию, к которой присоединен интерфейс A (это может потребовать больше работы, чем просто переопределение одной функции), что вы можете сделать так (пример должен быть полным, кроме определения загрузочного интерфейса):
#include <glib-object.h>
#include "fooable.h"
typedef struct {GObject parent;} A;
typedef struct {
GObjectClass parent;
gint (*foo) (Fooable *self, gdouble quux);
} AClass;
#define TYPE_A (a_get_type())
#define A_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), TYPE_A, AClass))
#define A_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_A, AClass))
gint a_foo_real (Fooable *self, gdouble quux) {
g_print("a_foo_real(%g)\n", quux);
return 5;
}
gint a_foo (Fooable *self, gdouble quux) {
return A_GET_CLASS(self)->foo(self, quux);
}
void implement_fooable (FooableIface *iface) {iface->foo = a_foo;}
void a_class_init (AClass *cls) {cls->foo = a_foo_real;}
void a_init (A *self) {}
G_DEFINE_TYPE_WITH_CODE(A, a, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(TYPE_FOOABLE, implement_fooable));
/* derive class B from A */
typedef struct {A parent;} B;
typedef struct {AClass parent;} BClass;
#define TYPE_B (b_get_type())
gint b_foo_real (Fooable *self, gdouble quux) {
g_print("b_foo_real(%g)\n", quux);
return 55;
}
void b_class_init (BClass *cls) {A_CLASS(cls)->foo = b_foo_real;}
void b_init (B *self) {}
G_DEFINE_TYPE(B, b, TYPE_A);
int main () {
g_type_init();
A *a = g_object_new(TYPE_A, NULL);
B *b = g_object_new(TYPE_B, NULL);
fooable_foo(FOOABLE(a), 87.0); // a_foo_real(87.0) and returns 5
fooable_foo(FOOABLE(b), 32.0); // b_foo_real(32.0) and returns 55
return 0;
}
Это не менее краткий пример, чем я могу сделать это. При вызове fooable _ foo ()
функция просматривает свою таблицу vtable для функции, определенной при реализации интерфейса a _ foo ()
, которая просматривает таблицу vtable класса A, чтобы определить, какую функцию следует фактически вызвать. Определение класса B переопределяет класс A a _ foo _ real ()
своим собственным. Если для цепочки требуется b _ foo _ real
класса B, это достаточно просто (используйте A _ CLASS (b_parent_class) - > foo ()
, который определен для вас в макросе G_DEFINE_TYPE)
Если все, что вы делаете, это вызываете ToString
, из-за полиморфного характера C # ToString вызовет правильную реализацию, даже если все, что у вас есть, является ссылкой на Object.
Например:
var d=DateTime.Now;
object od=d;
Console.WriteLine(od.ToString());
Console.WriteLine(d.ToString()); //same as previous line
edit
Если кому-то интересно, здесь коды тестов: http://gist.github.com/raw/305787/dc5349d9f6fa37ee5d621b43ec92dade60fe1c8d/ToStringTests.cs
Ниже вы найдете мой исходный ответ. Кто-то указал, что у вас может быть тип, который не имеет ToString (), который вам нравится (потому что он использует Object или что-то более высокое в цепочке). Лучший способ справиться с этим в версии 3.0+ - использовать такой метод расширения:
public static class ToStringExpander
{
public static string MyToString (this Object x)
{
return x.ToString();
}
public static string MyToString (this mytype x)
{
return "This is the to string of mytype!";
}
}
Теперь mytype будет работать с GetColumnValue, указанным ниже, если вы измените ToString () на MyToString ()
исходное сообщение
Это сделает то, что ты хочешь.
public string GetColumnValue(string columnName)
{
object value = item[columnName];
if (value == null)
return string.Empty;
return object.ToString();
}
или, если вы хотите выглядеть олдскульно:
public string GetColumnValue(string columnName)
{
return (item[columnName] == null ? string.Empty : item[columnName].ToString());
}
конечно, истинно олдскульный будет сделать макрос #define ...
В зависимости от вашего списка допустимых типов вы можете рассмотреть возможность использования Convert.ToString и / или интерфейса IConvertable .
Это позволит вам обрабатывать большинство примитивных типов за один раз.
Однако вам все равно придется обрабатывать вашу нулевую проверку.
Почему вы не можете просто использовать .ToString () для значения
, поскольку .ToString () наследуется от объекта? Будет вызвана функция .ToString () для соответствующего типа, расположенного дальше по цепочке наследования.
ToString ()
- виртуальный метод. Это означает, что любые вызовы этого метода во время выполнения будут выбирать правильную реализацию («наиболее производный тип»). Поскольку все примитивные типы переопределяют ToString ()
, чтобы делать правильные вещи, нет причин для какого-либо преобразования к любому типу переменной.
Для виртуального метода тип переменной не имеет значения при выборе правильной реализации. Все, что имеет значение, - это тип объекта, на который имеется ссылка.
int x = 10;
object o = x;
x.ToString();
o.ToString();
Оба вызова ToString ()
будут выполнять один и тот же код (за вычетом распаковки, которая происходит в версии объекта
, поскольку int
является типом значения) .