.Net interface for a known return type, but unknown type/number of parameters
Is ther开发者_开发百科e a way to specify in an interface a known return type, but unknown number/type of parameters.
The reason I am asking is that I am using Windows Azure Table Storage and each table will have different Partition and Row keys with different input values.
I am creating a ITableOperations
interface the code will be something like:
interface ITableOperations<T>
where T : Azure.AzureTableEntity
{
// Key specification
string PartitionKey(/* ? What should go here */);
// Key specification
string RowKey(/* ? What should go here */);
}
And the item table... For another table, the input params would be different
public class ScheduledItem : ITableOperations<ScheduledPostEntity>
{
public string PartitionKey(Guid userGuid)
{
return userGuid.ToString();
}
public string RowKey(DateTime dateScheduled)
{
return dateScheduled.ReverseTicks();
}
}
You could try having a very generic interface. For example:
interface ITableOperations<T, P, R>
where T : Azure.AzureTableEntity
{
string PartitionKey(P partitionKey);
string RowKey(R rowKey);
}
Then your implementation could be:
public class ScheduledItem : ITableOperations<ScheduledPostEntity, Guid, DateTime>
{
public string PartitionKey(Guid userGuid)
{
return userGuid.ToString();
}
public string RowKey(DateTime dateScheduled)
{
return dateScheduled.ReverseTicks();
}
}
EDIT:
Looking at some of your comments since I originally wrote this answer, you could come at it from a different angle. The PartitionKey and RowKey won't change on your object once it has been created, so I'd almost take these particular functions out of this class and move it to the constructors of the classes that inherit from 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;
}
}
This has the advantage that whenever you create on of these objects, you know minimum requirements to save the object. It also stops you from messing with things that will change your PK and RK.
C# supports multiple parameter in the form of an array by using the params
keyword.
You could do this:
interface ITableOperations<T>
where T : Azure.AzureTableEntity
{
// Key specification
string PartitionKey(params object[] data);
// Key specification
string RowKey(params object[] data);
}
If you already know the alternatives of parameters, then you can use overload. Lets say you have a method that can either receive a string or a Guid or both, you could do this:
string PartitionKey(Guid guid);
string PartitionKey(string str);
string PartitionKey(Guid guid, string str);
If you are using C# 4, then you can use optional parameters:
string PartitionKey(Guid guid = default(Guid), string str = null);
You could define one parameter, which would be an array. This array would contain name/value pairs and could have as many as you need. I think this would give you the flexibility you're looking for.
This still won't show you the proper list of parameters for DoStuff (you'll just see params object[]
) but it's about as flexible as you'll get. Note that I've implemented the method explicitly in the implementing class so you don't see it in Intellisense if "foo" is declared as a Foo
rather than an 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]);
}
}
精彩评论