.Net интерфейс для известного типа возвращаемого значения, но неизвестного типа / количества параметров - PullRequest
7 голосов
/ 16 мая 2011

Есть ли способ указать в интерфейсе известный тип возвращаемого значения, но неизвестный номер / тип параметров.

Причина, по которой я спрашиваю, заключается в том, что я использую Windows Azure Table Storage, и каждая таблица будет иметь разные ключи Partition и Row с разными значениями ввода.

Я создаю интерфейс ITableOperations, код будет выглядеть примерно так:

interface ITableOperations<T>
    where T : Azure.AzureTableEntity
{
    // Key specification
    string PartitionKey(/* ? What should go here  */);

    // Key specification
    string RowKey(/* ? What should go here  */);
}

И таблица элементов ... Для другой таблицы параметры ввода будут другими

public class ScheduledItem : ITableOperations<ScheduledPostEntity>
{
    public string PartitionKey(Guid userGuid)
    {
        return userGuid.ToString();
    }
    public string RowKey(DateTime dateScheduled)
    {
        return dateScheduled.ReverseTicks();
    }
}

Ответы [ 4 ]

3 голосов
/ 16 мая 2011

Вы можете попробовать иметь очень общий интерфейс.Например:

interface ITableOperations<T, P, R>
    where T : Azure.AzureTableEntity
{
    string PartitionKey(P partitionKey);

    string RowKey(R rowKey);
}

Тогда ваша реализация может быть:

public class ScheduledItem : ITableOperations<ScheduledPostEntity, Guid, DateTime>
{
    public string PartitionKey(Guid userGuid)
    {
        return userGuid.ToString();
    }
    public string RowKey(DateTime dateScheduled)
    {
        return dateScheduled.ReverseTicks();
    }
}

РЕДАКТИРОВАТЬ:

Глядя на некоторые из ваших комментариев, так как я изначальнонаписал этот ответ, вы могли бы прийти к нему под другим углом.PartitionKey и RowKey не будут меняться в вашем объекте после его создания, поэтому я бы почти исключил эти конкретные функции из этого класса и переместил бы его в конструкторы классов, которые наследуются от AzureTableEntity.например,

public class ScheduledPostEntity : Azure.AzureTableEntity
{
    private Guid _userGuid;
    private DateTime _dateScheduled;

    public ScheduledPostEntity()
    {
        // Needed for deserialisation from Azure Table Storage
    }

    public ScheduledPostEntity(Guid userGuid, DateTime dateScheduled)
    {
        _userGuid = userGuid;
        _dateScheduled = dateScheduled;
    }

    public string PartitionKey
    {
        get { return _userGuid.ToString(); }
        set { _userGuid = Guid.Parse(value); }
    }

    public string RowKey
    {
        get { return _dateScheduled.ReverseTicks(); }
        set { _dateScheduled = value.FromReverseTicks(); }
    }

    // These are functions to avoid them being saved as additional properties
    // in Azure Table Storage.  Sometimes you can get away with them being
    // read only properties, but it depends on the type.
    public DateTime DateScheduled()
    {
        return _dateScheduled;
    }

    public Guid UserGuid()
    {
        return _userGuid;
    }
}

Это имеет то преимущество, что всякий раз, когда вы создаете один из этих объектов, вы знаете минимальные требования для сохранения объекта.Это также мешает вам возиться с вещами, которые изменят ваш PK и RK.

2 голосов
/ 16 мая 2011

C # поддерживает несколько параметров в виде массива с помощью ключевого слова params.

Вы можете сделать это:

interface ITableOperations<T>
    where T : Azure.AzureTableEntity
{
    // Key specification
    string PartitionKey(params object[] data);

    // Key specification
    string RowKey(params object[] data);
}

Если вы уже знаете альтернативы параметров, то вы можете использовать перегрузку. Допустим, у вас есть метод, который может принимать строку, Guid или оба, вы можете сделать это:

    string PartitionKey(Guid guid);
    string PartitionKey(string str);
    string PartitionKey(Guid guid, string str);

Если вы используете C # 4, то вы можете использовать дополнительные параметры:

    string PartitionKey(Guid guid = default(Guid), string str = null);
2 голосов
/ 16 мая 2011

Это все равно не покажет вам правильный список параметров для DoStuff (вы просто увидите params object[]), но он настолько гибок, насколько вы получите.Обратите внимание, что я реализовал метод явно в классе реализации, поэтому вы не увидите его в Intellisense, если «foo» объявлен как Foo, а не IFoo.

class Program
{
    static void Main(string[] args)
    {
        IFoo foo = new Foo();
        foo.DoStuff(Guid.NewGuid());
    }
}

public interface IFoo
{
    void DoStuff(params object[] args);
}

public class Foo : IFoo
{
    public void DoStuff(Guid arg)
    {
    }

    void IFoo.DoStuff(params object[] args)
    {
        if (args.Length != 1) throw new ArgumentException("args");
        if (args[0].GetType() != typeof(Guid)) throw new ArgumentException("args");
        DoStuff((Guid)args[0]);
    }
}
2 голосов
/ 16 мая 2011

Вы можете определить один параметр, который будет массивом. Этот массив будет содержать пары имя / значение и может иметь столько, сколько вам нужно. Я думаю, что это даст вам гибкость, которую вы ищете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...