【问题标题】:.Net interface for a known return type, but unknown type/number of parameters.Net 接口,用于已知返回类型,但未知类型/参数数量
【发布时间】:2011-08-26 02:59:26
【问题描述】:

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

我问的原因是我使用的是 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();
    }
}

【问题讨论】:

  • 这个界面怎么用?
  • 我只是想确保每个使用这个接口的类都有返回字符串的方法RowKey、PartitionKey... ITableOperations中还有其他操作,基本上是CRUD操作。

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


【解决方案1】:

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

【讨论】:

  • 谢谢,但理想情况下,特别是在编码时,我希望看到签名,这样我就知道要传递什么了。我确实考虑过params object
  • @Jason 我这里有使用 params 关键字的代码。我会发布它,但它仍然不知道。
  • 我认为“确切地知道要传入什么”可能与想要“未知数量/类型的参数”相互排斥。您可以为每个签名重载该方法,但我认为这将是很多重载。也许我不明白。
【解决方案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);

【讨论】:

  • 基本上,我所追求的简短答案似乎无法完成。似乎使用 params object[] 是一种方式。谢谢大家。我已将此标记为正确答案,因为 Miguel 是第一个回答它的人,但每个人都大致回避了相同的答案
【解决方案3】:

这仍然不会向您显示 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]);
    }
}

【讨论】:

    【解决方案4】:

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

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

    编辑:

    自从我最初写这个答案以来,看看你的一些 cmets,你可以从不同的角度来看待它。 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 的事情。

    【讨论】:

    • 也感谢您的回答。一个好主意,但不完全适合我所追求的,因为 partitionKey/RowKey 可以由许多属性组成!我希望 Azure Table Storage 可以快点,让我们更多地控制可以索引哪些列!
    • 好的,我已经添加了另一个可能对您有所帮助的想法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-26
    相关资源
    最近更新 更多