Как переключаться между "возможным" типом объекта?

Возможный дубликат:
С# - Есть ли более эффективная альтернатива, чем это для типа включения?

У моего устаревшего кода компании есть что-то, что следует за

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 или соответствующий тип с нулевым значением