Yeah, I know there aren't any virtual static members in c#, but I have a problem where they would be really helpful and I can't see a good way to proceed.
I've got a standard kind of system where I send packets of data over a communication channel and get back responses. The communication system needs to know how many bytes of response to wait for, and the length of the response is fixed for each command type, so I have this code defined:
public abstract class IPacket
{
public abstract int ReceiveLength { get; }
public abstract byte[] DataToSend();
}
public class Command1 : IPacket
{
public override int ReceiveLength { get { return 3; } }
public Command1() { }
}
public class Command2 : IPacket
{
public override int ReceiveLength { get { return DataObject.FixedLength; } }
public Command2(int x) { }
}
public class Command3 : IPacket
{
static DataHelperObject Helper;
public override int ReceiveLength { get { return Helper.DataLength(); } }
static Command3()
{
Helper = new DataHelperObject();
}
public Command3(really long list of parameters containing many objects that are a pain to set up) { }
}
Notice that in each case, ReceiveLength is a fixed value - sometimes it's a simple constant (3), sometimes it's a static member of some other class (DataObject.FixedLength) and sometimes it's the return value from a member function of a static member (Helper.DataLength()) but it's always a fixed value.
So that's all good, I can write code like this:
void Communicate(IPacket packet)
{
Send(packet.DataToSend());
WaitToReceive(packet.ReceiveLength);
}
and it works perfectly.
But now I would like to output a summary of the packets. I want a table that shows the command name (the class name) and the corresponding ReceiveLength. I want to be able to write this (pseudo)code:
foreach (Class cls in myApp)
{
if (cls.Implements(IPacket))
{
Debug.WriteLine("Class " + cls.Name + " receive length " + cls.ReceiveLength);
}
}
But of course ReceiveLength requires an object.
I don't think I can use attributes here, c# won't let me say:
[PacketParameters(ReceiveLength=Helper.DataLength())]
public class Command3 : IPacket
{
static DataHelperObject Helper;
static Command3()
{
Helper = new DataHelperObject();
}
public Command3(really long list of parameters containing many objects that are a pain to set up) { }
}
because custom attributes are created at compile time (right?), long before the static constructor gets called.
Constructing objects of each type isn't particularly pleasant (pseudocode again):
foreach (Class cls in myApp)
{
IPacket onePacket;
if (cls is Command1)
onePacket = new Command1();
else if (cls is Command2)
onePacket = new Command2(3);
else if (cls is Command3)
{
Generate a bunch of objects that are a pain to create
onePacket = new Command3(those objects);
}
Debug.WriteLine("Class " + cls.Name + " receive length " + onePacket.ReceiveLength);
}
I need ... a virtual static property.
One solution would be to throw all compile-time safety over board and simply use reflection to access your static property like so: http://fczaja.blogspot.ch/2008/07/accessing-static-properties-using-c.html
Alternatively, you could separate out that information into a "PaketSizeManager" type which would simply have either the above-mentioned Dictionary or some switch-case statement plus some neat way to access this information from the outside, as in a public int GetSize(Type t){ .../* use dictionary or switch-case here */... } method. That way you would have encapsulated the size aspect of all your entities into a separate class.
Just make a public static CommandX.Length property, have it return what your ReceiveLength property is now, then have ReceiveLength refer to it. To get the best of both worlds, first you need both worlds.
Related
I'm tring to create a list of different types object that derivated from the same parent and access its custom properties.
These are my classes:
abstract class Signal
{
}
abstract class Signal<T>:Signal
{
public T Value { get ; set; }
public Signal(T value)
{
Value = value;
}
}
class scalar_signal : Signal<int>
{
public scalar_signal(int value):base(value)
{
}
}
class array_byte_signal: Signal<byte[]>
{
public array_byte_signal(byte[] value):base(value)
{
}
public override string ToString()
{
return string.Join("; ", Value);
}
}
And this is my program:
static void Main(string[] args)
{
var signals = new List<Signal>();
signals.Add(new scalar_signal(3));
signals.Add(new array_byte_signal(new Byte[] { 0, 1 }));
foreach (var signal in signals)
{
Console.WriteLine(signal.Value); //Compilation error: Value is not defined in Signal
}
}
As you can see I'm able to create a list of different types of signals but I'm not able to access their properties.
I really need to have only one list (or any other collection) with all my signals becuase later on it will be easier to process.
I have to implement one class for each type of signals as they need to implement a custom behavior depending of the type T. T could be also a class representing a complex number, matrix, etc.
I have read about Covariance and contravariance but I do not see how this could help me.
Thank you for your help.
this is because
when you looping
foreach (var signal in signals)
{
Console.WriteLine(signal.Value); //Compilation error: Value is not defined in Signal
}
the type is Signal
which as you now has no property.
what you need to do it ask it if its able to be something else,
foreach (var signal in signals)
{
//#6
if(signal is scalar_signal)
{
var typeCast = (scalar_signal)signal;
Console.WriteLine(typeCast .Value);
}
//#7.2 +
if(signal is scalar_signal valueTypeName)
{
Console.WriteLine(valueTypeName.Value);
}
}
this should help
I want to create a structure to store data consumed from a Web Service with the followind specs:
Response:
Field 1 - InstructionType: Can be 1 (PreferredDay), 2 (SVP), 3 (Neighbour)
Field 2: Some variable data. Its type depends on Field 1. So if:
Field 1 == 1 then Field 2 type will be of DateTime (dd.MM.yyyy)
Field 1 == 2 then Field 2 type will be of type string.
Field 1 == 3 then Field 2 type will be of type string
So, I started up with the following enum:
public enum InstructionType
{
None = 0,
PreferredDay = 1,
ServicePoint = 2,
Neighbour = 3
}
And the generic class:
public abstract class Instruction<T>
{
public InstructionType Type { get; private set; }
public T Data { get; private set; }
public Instruction(InstructionType type, T data)
{
this.Type = type;
this.Data = data;
}
}
and concrete classes:
public class PreferredDayInstruction : Instruction<DateTime>
{
public PreferredDayInstruction(DateTime data)
: base (InstructionType.PreferredDay, data) {}
}
public class ServicePointInstruction: Instruction<string>
{
public ServicePointInstruction(string data)
: base (InstructionType.ServicePoint, data) {}
}
public class NeughbourInstruction: Instruction<string>
{
public NeughbourInstruction(string data)
: base (InstructionType.Neighbour, data) {}
}
When parsing web service's response created a public function:
public Instruction DeliveryInstruction() <---Compiler error here "Instruction"
{
if (resultFromWebservice.Field1 == 1)
return new PreferredDayInstruction((DateTime)Field2);
if (resultFromWebservice.Field1 == 2)
return new ServicePointInstruction(Field2);
if (resultFromWebservice.Field1 == 3)
return new NeighbourInstruction(Field2);
}
and here is the problem. Can't return objects of generic type.
Tried with with Interface, factories, and other stuff, but allways with the same problem. So, is there any way to archieve this? maybe it's not possible or maybe is so easy I can't see now. Thanks in advance.
UPDATE:
Compiler error on BOLD Instruction
Error 1 Using the generic type 'NAMESPACE.Instruction' requires '1' type arguments
I forgot..I'm using .NET 3.5
It looks like you may be starting off with an intent to use generics rather than using them because you've identified a need. Often (not always) when that gets difficult it's because it didn't actually fit what you were trying to do.
What seems odd in this case is that you have both a generic type and an enum to indicate the type. This is likely to cause you a few problems.
First it looks like you're trying to create a one-size-fits all class to model different types of behaviors. That will start off confusing and get more confusing. Think of most classes that are part of the .NET framework, and imagine what would happen if they had properties like Field1 and Field2, and you couldn't tell from looking at them what they were for. And in one method they're used for one thing, but in a another case they mean something else.
Also, if you're trying to put different types of instructions in one class, that suggests that maybe you're going to try passing them all to one method, and that method figures out what to do, and maybe calls other methods. (I'm guessing that because of the enum. Perhaps you're going to handle the input differently depending on which value it contains.) That one method will get really hard to maintain.
I'd recommend waiting on generics until you're sure you need them. And if you have different types of instructions you're likely better off writing a different class for each one with the properties it needs and names that describe them, and writing methods for each of them to do what they need to do. If you need lots of classes, make lots of them.
It's very easy to fall into the trap of trying to solve problems that don't exist, like how do I write one class that covers a bunch of different needs. The answer usually that you don't need to. You'll get better results from writing more classes that each do fewer things.
Believe me that I tried to do my best to explain what was my problem and what I needed in order to solve it. In a nutshell, the question was quite simple. Is this possible or not? So, is there a way to return a common type for these 3 classes? Answer is no, as they don't share any root. They all derive from Instruction, but aren't compatible each other. That's what I learned from this experience.
As another example, lets take another .NET framework's generic type.
public class ListOfString : List<string> { }
public class ListOfInt : List<int> { }
public class ListOfDecimal : List<decimal> { }
And, in another place of the application, get a method who returns one of this List based on some logic:
public class Logic
{
public List<> GetList(Type t) <----This can't be done
{
if (t == typeof(string))
return new ListOfString();
if (t == typeof(int))
return new ListOfInt();
if (t == typeof(decimal))
return new ListOfDecimal();
else return null;
}
}
Please, keep in mind that this is just a stupid sample just to show what's the point of this post.
By the way, in the case of List the following can be done, because there is a non generic different version of IList:
public IList GetList(Type t)
{
....
}
But I can't think of a way to do this in my particular case.
Anyway, I finally followed another approach. I reallized that what I really wanted is to ensure Data property is valid. If it it's supposed to be a date there, ensure date is valid. Is it a string, ensure it has the right length or whatever rule it must follow.
So this is the final solution:
The enum:
public enum InstructionType
{
None = 0,
PreferredDay = 1,
ServicePoint = 2,
Neighbour = 3
}
The base class:
public abstract class Instruction
{
public InstructionType Type { get; private set; }
public string Data { get; private set; } <---Type String
public Instruction(InstructionType type, string data)
{
this.Type = type;
this.Data = IsValid(data) ? data : string.Empty;
}
public abstract bool IsValid(string data); <--the rule.
}
The concrete classes:
public class PreferredDayInstruction : Instruction
{
public PreferredDayInstruction(string date)
: base(InstructionType.PreferredDay, date) { }
public override bool IsValid(string data)
{
string[] formats = {"dd.MM.yyyy", "d.MM.yyyy",
"dd.MM.yy", "d.MM.yy"};
try
{
data = data.Replace('/', '.').Replace('-', '.');
var dateparts = data.Split('.');
DateTime date = new DateTime(Convert.ToInt32(dateparts[2]),
Convert.ToInt32(dateparts[1]),
Convert.ToInt32(dateparts[0]));
//DateTime.ParseExact(data, formats, null, System.Globalization.DateTimeStyles.AssumeLocal);
return true;
}
catch (Exception)
{
return false;
}
}
}
public class ServicePointInstruction : Instruction
{
public ServicePointInstruction(string data)
: base (InstructionType.ServicePoint, data) { }
public override bool IsValid(string data)
{
return ServicePointBarcodeValidator.Validate(data);
}
}
public class NeighbourInstruction : Instruction
{
public NeighbourInstruction(string data) :
base(InstructionType.Neighbour, data) { }
public override bool IsValid(string data)
{
return data.Length <= 70;
}
}
A factory class, who's responsability is to create and return the correct object based on the enum:
public static class DeliveryInstructionFactory
{
public static Instruction Create(int type, string data)
{
return Create((InstructionType)type, data);
}
public static Instruction Create(InstructionType type, string data)
{
switch (type)
{
case InstructionType.PreferredDay:
return new PreferredDayInstruction(data);
case InstructionType.ServicePoint:
return new ServicePointInstruction(data);
case InstructionType.Neighbour:
return new NeighbourInstruction(data);
default:
return null;
}
}
}
And finally, as now all of they share the same root, object can be created on webservice's response parser:
public Instruction DeliveryInstruction()
{
try
{
int instructionCode = int.Parse(observation.Substring(173,2));
string instructionData = observation.Substring(175, 10);
return DeliveryInstructionFactory.Create(instructionCode, instructionData); }
catch (Exception ex)
{
Log.Error("[ValidationBarcodeResponse] DeliveryInstructions aren't in the correct format", ex);
return null;
}
}
Hope this now fits on a Minimal, Complete, and Verifiable example
There is a very easy trick which creates a dictionary-like structure where keys are types.
The structure acts like a Dictionary<Type, T?> where keys are Type objects and values are instances of the corresponding types.
This wonderful structure is as fast as just a variable or array since the "lookup" is only done once by the compiler/JITter and the proper value reference is compiled into your program.
public static class MyDict<T> {
public static T Value { get; set; }
}
You can work with that structure like this:
MyDict<string>.Value = MyDict<int>.Value.ToString();
The problem is that this "dictionary" is global. The only way to create different dictionaries is to create different classes.
How can create a similar (fastest "lookup", no boxing) non-static structure? (Without code generation.)
Simply said: I want to have multiple Dictionary<Type, object>-like objects without lookup costs, casting and boxing.
Here's an approach that extends the method described in the question:
public class TypeDict
{
public T Get<T>()
{
return MyDict<T>.Values[this];
}
public void Set<T>(T value)
{
MyDict<T>.Values[this] = value;
}
private static class MyDict<T>
{
public static Dictionary<TypeDict, T> Values { get; private set; }
static MyDict()
{
Values = new Dictionary<TypeDict, T>();
}
}
}
Now we can use the TypeDict like this:
void X()
{
var a = new TypeDict();
var b = new TypeDict();
a.Set<int>(1);
a.Set<double>(3.14);
a.Set("Hello, world!");
//Note that type inference allows us to omit the type argument
b.Set(10);
b.Set(31.4);
b.Set("Hello, world, times ten!");
Console.WriteLine(a.Get<int>());
Console.WriteLine(a.Get<double>());
Console.WriteLine(a.Get<string>());
Console.WriteLine();
Console.WriteLine(b.Get<int>());
Console.WriteLine(b.Get<double>());
Console.WriteLine(b.Get<string>());
}
Ark-kun is using generics to essentially generate unique types at compile time. With a generic type, any static members are unique to that specific closed generic type. This way it's processed as fast as a standard static member lookup.
The above usage is equivalent to something like this:
public static class MyDict_String
{
public static string Value { get; set; }
}
public static class MyDict_Int32
{
public static int Value { get; set; }
}
MyDict_String.Value = MyDict_Int32.Value.ToString();
AFAIK, types are "static" (in that you can't define more than one that way) so I don't know of a way to cheat around this and maintain the same performance of a statically compiled member lookup.
Your best bet otherwise (I think) is to create a generic instance type that wraps its own dictionary that uses System.Type for its keys and System.Object for its values to which you have to perform boxing/casting when inserting/retrieving values.
EDIT: Here's a simple implementation wrapping a dictionary:
public class MyTypedDict
{
private Dictionary<Type, object> Values = new Dictionary<Type, object>();
public T Get<T>()
{
object untypedValue;
if (Values.TryGetValue(typeof(T), out untypedValue))
return (T)untypedValue;
return default(T);
}
public void Set<T>(T value)
{
Values[typeof(T)] = value;
}
}
Thinking about it more, it might be possible to achieve a more property-like syntax using an ExpandoObject (http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx) through some tomfoolery, but I feel like this would be pretty abusive and I can only assume terribly prone to runtime errors. (plus it would afford you nothing at compile time)
EDITx2: If you really want to have different sets of values, you could nest it within another generic type:
public static class ValueSets<T>
{
public static class MyDict<U>
{
public static U Value { get; set; }
}
}
With usage like:
ValueSets<int>.MyDict<string>.Value = "Hello ";
ValueSets<bool>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<int>.MyDict<string>.Value + ValueSets<bool>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
But then the initial type int and bool in this case become "magical" and without meaning, plus you would need to provide a unique type per distinct set of values you'd like to use. Plus you could not pass it around and modify as an instance variable, rather it'd be statically accessible (so long as you have access to use the type T). So perhaps you could declare minimally visible types that are named with meaning and use those:
internal class MyFirstWords {}
internal class MySecondWords {}
ValueSets<MyFirstWords>.MyDict<string>.Value = "Hello ";
ValueSets<MySecondWords>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<MyFirstWords>.MyDict<string>.Value + ValueSets<MySecondWords>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
Regardless, I think this is quite wacky and I wouldn't recommend it.
A more complicated version. Don't know if it's closer:
Define a generic dictionary:
public class MyDictionary<T>
{
Dictionary<string, T> dict;
public MyDictionary()
{
dict = new Dictionary<string, T>();
}
public T this[string name]
{
get
{
if (dict.ContainsKey(name))
return dict[name];
else
return default(T);//or throw
}
set
{
dict[name] = value;
}
}
}
Then a repository to store those dictionaries:
public class MyRepository
{
List<object> repo;
public MyRepository()
{
repo = new List<object>();
}
public void Add<T>(string name, T value)
{
if (!repo.OfType<MyDictionary<T>>().Any())
repo.Add(new MyDictionary<T>());
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
dict[name] = value;
}
public T GetValue<T>(string name)
{
if (!repo.OfType<MyDictionary<T>>().Any())
return default(T);//or throw
else
{
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
return dict[name];
}
}
}
And finally you may use this repository:
MyRepository repo = new MyRepository();
repo.Add("A", 1);
repo.Add("B", 1);
int i = repo.GetValue<int>("A") + repo.GetValue<int>("B");
In this example, there is MyDictionary<T> boxing to object is left.
From the other side, if your are working with some certain types you may not use thie repository class at all. But utilize separate dictionaties.
MyDictionary<int> intDict = new MyDictionary<int>();
intDict["A"] = 1;
intDict["B"] = 2;
int i = intDict["A"] + intDict["B"];
However it's the same as working with
Dictionary<string, int> intDict = new Dictionary<string, int>();
So the MyRepository class may be edited to use Dictionary<string, T> instead of MyDictionary<T>.
#Konstantin's answer made me remember that there is actually a very fast lookup method - array indexing. This crude PoC code shows a variant of the required structure.
public class TypeDictionary {
static int _maxId = 0;
int _id;
static class Store<T>{
internal static List<T> Values = new List<T>();
}
public TypeDictionary() {
_id = _maxId++;
}
public T GetValue<T>() {
return Store<T>.Values[_id];
}
public void SetValue<T>(T value) {
while(Store<T>.Values.Count < _id) {
Store<T>.Values.Add(default(T));
}
Store<T>.Values[_id] = value;
}
}
This code can be used as follows:
var dict1 = new TypeDictionary();
dict1.SetValue("my string");
string result = dict1.GetValue<string>();
The problem with this solution is it's memory usage caused by the repository being not sparse. This also makes first time value setting more expensive.
Try this:
public class MyDictionary
{
List<object> values;
public MyDictionary()
{
values = new List<object>();
}
public T GetValue<T>()
{
return values.OfType<T>().FirstOrDefault();
}
public bool Add<T>(T value)
{
if (values.OfType<T>().Any())
return false;
else
{
values.Add(value);
return true;
}
}
}
and use it:
var md = new MyDictionary();
md.Add("!!!");
string s = md.GetValue<string>();
This class may store up to one value of type T. But there could corner cases with derived classes and interfaces I guess. You may check, if it suits your need, and probably modify it as you need, if it's close to what you need in general.
What you are looking for is impossible in C#. The language does not support a container that could store multiple objects of different types yet provides a look up method that does not involve casting, boxing or unboxing. You could accomplish something like this with macros in C++, or via a language like javascript where the structure of types can be changed at run-time.
The usage case you are describing fits quite closely with the purpose for which ConditionalWeakTable<TKey,TValue> was added to .NET 4.0. For the purpose you describe, you would include such a table in a static generic class, and then for every class object that's supposed to contain a reference to an item of a particular type you would store into that type's table a reference to object that's supposed to contain the item along with either a reference to the item, or else a reference to a simple item-holder object (note that entries in ConditionalWeakTable will evaporate when an object ceases to exist, but are otherwise immutable, so if you want a mutable association you'll need to create an object to hold it).
Building on #phoog's example with #supercat's suggestion
public class TypeDict
{
public T Get<T>() where T : class
{
T value;
InnerDict<T>.Values.TryGetValue(this, out value);
return value;
}
public void Set<T>(T value) where T : class
{
var cwt = InnerDict<T>.Values;
// lock+remove+add https://github.com/dotnet/coreclr/issues/4545
lock (cwt)
{
cwt.Remove(this);
cwt.Add(this, value);
}
}
private static class InnerDict<T> where T : class
{
public static ConditionalWeakTable<TypeDict, T> Values { get; private set; }
static InnerDict()
{
Values = new ConditionalWeakTable<TypeDict, T>();
}
}
}
I'm going to do my best to explain my vision here. This is a very lame made-up example. I've got a few different types of Bags, and they all hold their own special type of Marble. Each type of Marble has its own set of Nicknames (strings).
Unfortunately, there are other things besides the Marble in the Bag, so generics won't help me here.
// Bags
abstract class Bag {
protected Type MarbleType { get; }
protected List<Marble> _marbles;
public void DumpBag()
{ ... }
}
class RedBag : Bag {
override Type MarbleType { get { return typeof(RedMarble); } }
}
class BlueBag : Bag {
override Type MarbleType { get { return typeof(BlueMarble); } }
}
// Marbles
abstract class Marble {
public static IEnumerable<string> Nicknames {
get {
return new List<string>() {
"Marble", "RollyThing"
}
}
}
}
class RedMarble : Marble {
public static IEnumerable<string> Nicknames {
get {
return new List<string>(Marble.Nicknames) {
"Ruby"
};
}
}
}
class BlueMarble : Marble { ... }
So now we get to the details, the implementation of DumpBag(). Consider the following call:
Bag b = new RedBag();
b.GetMarbles();
b.DumpBag();
I would like it to print:
Bag of Marbles (aka "Marble", "RollyThing", Ruby"):
- Marble 1
- Marble 2
...
We see that, in order to print that heading, the Bag must be able to have knowledge of the derived type of Marble, independent of any actual instances. It gets a concatenation of the Nicknames of the Marble base class, but also the derived RedMarble.
DumpBag needs to do a kind of 'static virtual call'. I've started implementing DumpBag with the following:
public void DumpBag() {
PropertyInfo pi = this.MarbleType.GetProperty("Nicknames", BindingFlags.Static);
IEnumerable<string> nicknames = pi.GetValue(null, null); // No instance
StringBuilder sb = new StringBuilder("Bag of Marbles (aka ");
foreach (string nn in nicknames)
sb.Append("\"" + nn + "\", ");
Console.WriteLine(sb.ToString());
...
}
My questions:
Is this sane? Hopefully I have (or I can) explain my rationale for why I've gone this route.
I get a warning (of course) that RedMarble.Nicknames hides Marble.Nicknames. Does it seem valid to go ahead and mark it new?
You'll find all you're missing is an explicit cast:
(List<string>)this.MarbleType.GetProperty("Nicknames").GetValue(null, null);
This worked fine for me when I tested it.
And as discussed in the comments, no you shouldn't be using the new keyword really, you're better off naming the base class static method to something else so there is no ambiguity. You are after all in control of this and not using someone else's code.
Now, should you do it this way?
Well, first surely you want to use generics not defined methods to return types:
abstract class Bag<T> where T:marble {
public void DumpBag()
{
// here you can use
// (IEnumerable<string>)typeof(T).GetProperty("Nicknames").GetValue(null, null);
}
}
class RedBag : Bag<RedMarble> {
}
class BlueBag : Bag<BlueMarble> {
}
Of course the second thing you could do is make this not static, in which case the property will be abstract in Marble, and overridden in RedMarble and BlueMarble, and then just accessed in DumpBag directly as Nicknames rather than using reflection.
Is there 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]);
}
}