Как переключаться между "возможным" типом объекта?
Возможный дубликат:
С# - Есть ли более эффективная альтернатива, чем это для типа включения?
У моего устаревшего кода компании есть что-то, что следует за
public override Uri GetUri(object obj)
{
if ((obj is Entry) || (obj is EntryComment))
{
//
}
if (obj is Blog)
{
//
}
// if obj is blah blah blah
}
Этот метод просто уродлив. Я хочу реорганизовать его, но я не знаю техники для повторения "возможных" типов, которые могут быть obj.
Как я могу реорганизовать это?
Спасибо.
Ответы
Ответ 1
Вы также можете реорганизовать это с помощью интерфейсов
public interface IHasUri
{
public Uri GetUri();
}
и реализовать этот интерфейс во всей иерархии. Чем вы можете использовать
public Uri GetUri(object obj)
{
IHasUri hasUri = obj as IHasUri;
if(hasUri != null)
Uri uri = hasUri.GetUri();
// bla bla bla
}
Ответ 2
Несколько вариантов:
-
Если вы используете С# 4, вы можете использовать динамическую типизацию и разбить метод на несколько перегрузок:
public Uri GetUri(dynamic obj)
{
return GetUriImpl(obj);
}
private Uri GetUriImpl(Entry entry)
{
...
}
private Uri GetUriImpl(EntryComment comment)
{
...
}
В этом случае вам, вероятно, понадобится какой-то метод "обратного хода", если он не известен.
-
Вы можете создать Dictionary<Type, Func<object, Uri>>
:
private static Dictionary<Type, Func<object, Uri>> UriProviders =
new Dictionary<Type, Func<object, Uri>> {
{ typeof(Entry), value => ... },
{ typeof(EntryComment), value => ... },
{ typeof(Blog), value => ... },
};
а затем:
public Uri GetUri(object obj)
{
Func<object, Uri> provider;
if (!UriProviders.TryGetValue(obj.GetType(), out provider))
{
// Handle unknown type case
}
return provider(obj);
}
Обратите внимание, что это не будет охватывать случай, когда вы получаете подтип Entry
и т.д.
Ни один из них не особенно приятен, заметьте... Я подозреваю, что более предпочтительным может быть редизайн более высокого уровня.
Ответ 3
Я думаю, что Лассе В. Карлсен имеет право на это в своих комментариях, редизайн более уместен, возможно,
Вы можете создать интерфейс, например, Stecya предлагает
public interface IUriAccessible { //or some sort of a more descriptive name
Uri Url {get;}
}
а затем для каждого объекта, который вам нужен, например Entry
, вы могли бы
public class Entry:IUriAccessible {
//... other code here
public Uri Url {
get {
//return uri here
}
}
}
и теперь вы можете просто вызвать его на объекте
var entry = new Entry();
var uri = entry.Url;
Ответ 4
У вас может быть List<Type>()
со всеми типами, которые вы хотите проверить, и повторите этот список. но я не думаю, что это делает код быстрее.
Ответ 5
Вы не можете использовать типы switch-case
.
Выражение switch или метка case должно быть bool, char, string, integer, enum или соответствующий тип с нулевым значением