.Net接口,用于已知的返回类型,但未知类型/数量的参数

时间:2011-05-16 01:11:34

标签: c# .net design-patterns interface azure

是否有办法在接口中指定已知的返回类型,但未知数量/类型的参数。

我问的原因是我使用的是Windows Azure表存储,每个表都有不同的分区和行键以及不同的输入值。

我正在创建一个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 个答案:

答案 0 :(得分:3)

您可以尝试使用非常通用的界面。例如:

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的类的构造函数。 e.g。

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的东西。

答案 1 :(得分:2)

您可以定义一个参数,即一个数组。此数组将包含名称/值对,并且可以包含您需要的任意数量。我认为这可以为您提供所需的灵活性。

答案 2 :(得分:2)

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);

答案 3 :(得分:2)

这仍然不会显示DoStuff的正确参数列表(您只会看到params object[]),但它会像您一样灵活。请注意,我已在实现类中显式实现了该方法,因此如果将“foo”声明为Foo而不是IFoo,则不会在Intellisense中看到它。

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]);
    }
}