Как я могу заставить это работать?
switch(property.PropertyType){
case typeof(Boolean):
//doStuff
break;
case typeof(String):
//doOtherStuff
break;
default: break;
}
Я не хочу использовать это имя, поскольку сравнение строк для типов просто ужасно и может быть изменено.





Не беспокойтесь об использовании строк в переключателе, потому что, если у вас их несколько, компилятор автоматически преобразует их в поиск по хешу, обеспечивая приличную производительность, несмотря на то, что это выглядит довольно ужасно.
Проблема изменения строк типа может быть решена путем самостоятельного преобразования ее в явный поиск по хешу и заполнения содержимого хеша в статическом конструкторе. Таким образом, во время выполнения хэш заполняется правильными строками, чтобы они оставались правильными.
Вы не можете сделать это с помощью switch в C#, поскольку регистр должен быть постоянным.
Что не так с:
if (property.PropertyType == typeof(bool)) {
//dostuff;
}
else if (property.PropertyType == typeof(string)) {
//do other stuff;
}
Просто используйте обычный шаблон if / else if / else:
if (property.PropertyType == typeof(Boolean))
{
}
else if (property.PropertyType == typeof(String))
{
}
else if (...)
{
}
System.Type propertyType = typeof(Boolean);
System.TypeCode typeCode = Type.GetTypeCode(propertyType);
switch (typeCode)
{
case TypeCode.Boolean:
//doStuff
break;
case TypeCode.String:
//doOtherStuff
break;
default: break;
}
Вы можете использовать гибридный подход для TypeCode.Object, где вы используете динамическое if с typeof. Это очень быстро, потому что для первой части - переключателя - компилятор может принять решение на основе таблицы поиска.
Не будет работать, если вы хотите сравнить что-либо, кроме простых встроенных типов, потому что TypeCode - это перечисление, которое не содержит ничего, кроме простых типов, таких как bool, int32 и т. д.
Конечно, это правда. Но из-за того, что в этом примере я не рассмотрел, я в первую очередь пропустил. Добавлено позже, чтобы прояснить этот момент. Спасибо.
Ну, в моем конкретном случае это будут только базовые типы.
Просто обратите внимание на это, если вы хотите, чтобы он работал для типов, допускающих значение NULL, вы должны проверить свойствоType.IsGenericType && propertyType.GetGenericTypeDefinition () == typeof (System.Nullable <>), а затем получить базовый тип ... вот пример: yakkowarner.com/2008/12/…
Вы не можете. Что вы можете сделать, так это создать сопоставление между типами и делегатом с помощью словаря:
var TypeMapping = new Dictionary<Type, Action<string>>(){
{typeof(string), (x)=>Console.WriteLine("string")},
{typeof(bool), (x)=>Console.WriteLine("bool")}
};
string s = "my string";
TypeMapping[s.GetType()]("foo");
TypeMapping[true.GetType()]("true");
Недавно мне пришлось сделать что-то подобное, и использование переключателя не было вариантом. Выполнение == для typeof (x) - это нормально, но может быть более элегантным способом сделать что-то вроде этого:
if (property.PropertyType is bool){
//dostuff;
}
else if (property.PropertyType is string){
//do other stuff;
}
Но я не уверен, что вы можете использовать ключевое слово «is» таким образом, я думаю, что оно работает только для объектов ...
Я думаю, что вы ищете здесь хорошую карту. Используя делегатов и Generic IDictionary, вы можете делать то, что хотите.
Попробуйте что-то вроде этого:
private delegate object MyDelegate();
private IDictionary<Type, MyDelegate> functionMap = new IDictionary<Type, MyDelegate>();
public Init()
{
functionMap.Add(typeof(String), someFunction);
functionMap.Add(tyepof(Boolean), someOtherFunction);
}
public T doStuff<T>(Type someType)
{
return (T)functionMap[someType]();
}
Лично я больше всего предпочитаю подход Dictionary<Type, other> ... Я даже могу предоставить вам другой пример: http://www.timvw.be/presenting-namevaluecollectionhelper/
Если вы настаиваете на написании оператора switch-case, вы можете использовать имя типа ...
switch (blah.PropertyType.FullName)
{
case typeof(int).FullName: break;
case typeof(string).FullName: break;
}
@nawfal Я проголосовал за это, потому что вы ошиблись. Он работает с System.String. System.String - неизменяемый тип.
@toATwork Неизменяемый или нет, case требует постоянного выражения. Например, если System.String в вашем примере выглядит как case "myCompileTimeValue":, это сработает. Но если он выглядит как case myRunTime.Value:, он не компилируется. Все может измениться в будущих версиях C# (возможно, 7) с сопоставлением с образцом и всем остальным.
@nawfal Вы правы! В моем случае это было что-то вроде "someString". Извинения. Надо было подумать об этом, прежде чем комментировать. Каждый случай должен быть уникальным и как гарантировать это с помощью переменной / свойства ... глупый я ...
О сопоставлении строк: одним из требований в вопросе было не выполнять это через сопоставление строк.
Словарь - это подход, который я буду использовать, когда помещу весь алгоритм сериализации в его собственную библиотеку. На данный момент я сначала попробую typeCode, поскольку в моем случае используются только базовые типы. Если это не сработает, я вернусь к рою if / elses: S
Прежде чем люди спросят меня, зачем мне нужна собственная сериализация: 1) .net xml-сериализация не сериализует свойства без сеттеров 2) сериализация должна соответствовать некоторым устаревшим правилам
Вы можете обойти ограничение свойств, добавив пустой набор. общедоступная строка MyProp {get {return foo;} set {;}}
C# 7.0 будет поддерживать типы включения как часть более крупной функции сопоставления с образцом. Этот пример взят из Сообщение в блоге .NET, который объявляет о новых функциях:
switch(shape)
{
case Circle c:
WriteLine($"circle with radius {c.Radius}");
break;
case Rectangle s when (s.Length == s.Height):
WriteLine($"{s.Length} x {s.Height} square");
break;
case Rectangle r:
WriteLine($"{r.Length} x {r.Height} rectangle");
break;
default:
WriteLine("<unknown shape>");
break;
case null:
throw new ArgumentNullException(nameof(shape));
}
OP, должно быть, уже это знает. Тем не менее +1 для противодействия голосованию против; тоже верное решение, иногда невозможно заменить мощность встроенных конструкций.