开发者

Getter property with arguments

I guess I've seen it somewhere before, but now I can't remember nor find it. Is there a way to make a getter prope开发者_如何学Pythonrty with arguments?

I mean, as I can convert "float getSize();" to "float Size":

float getSize() {
    return this.size;
}

float Size {
    get { return this.size; }
}

Then, could I convert, for example, "float getSize(String unit);" to "float Size(String unit)" or something like that?

float getSize(String unit) {
    return this.size;
}

float Size(String unit) {
    get {
        if (unit == Unit.Meters)
            return this.size/100;
        else
            return this.size;
    }
}

I think there's no really problem of using function at all, but may look better this way :P


To answer the question: No, it is not possible, and as already pointed out, a getter with a parameter would look just like a method.

The thing you are thinking about might be an indexed default property, which looks like this:

class Test
{
    public string this[int index] 
    {
        get { return index.ToString(); } 
    }
}

This allows you to index into an instance of Test, like this:

Test t = new Test();
string value = t[1];


Interestingly, having a property with parameter is possible in VB.NET, like this:

Public ReadOnly Property oPair(param As String) As Result
  Get
     'some code depends on param
  End Get
End Property

It's not superior to a regular function, but sometimes it is nice to have such a possibility.


I know this is an old post, but I ran into wanting to do this today in C#. Whether that's a good thing or not is probably falling on the 'not' side. However, I ran across an interesting idea posted by Mark Jones at (https://social.msdn.microsoft.com/forums/en-US/5a25bc83-990e-4657-aa9c-69bca5158d48/overloaded-c-properties-with-arguments?prof=required), but I didn't quite like the feel of it.

So I wrote my own based on his (mine is in .Net 5.0 with Nullable = enable):

class ParameterizedProperty<T>
{
    private readonly Func<int, T> getter;
    private readonly Action<int, T> setter;

    public T this[int index]
    {
        get => this.getter(index);
        set => this.setter(index, value);
    }

    public ParameterizedProperty(Func<int, T> getter, Action<int, T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
}

class NamedParameterizedProperty<T>
{
    private readonly Func<int, T> indexedGetter;
    private readonly Action<int, T> indexedSetter;
    private readonly Func<string, T> namedGetter;
    private readonly Action<string, T> namedSetter;

    public T this[int index]
    {
        get => this.indexedGetter(index);
        set => this.indexedSetter(index, value);
    }

    public T this[string name]
    {
        get => this.namedGetter(name);
        set => this.namedSetter(name, value);
    }

    public NamedParameterizedProperty(Func<int, T> indexedGetter, Action<int, T> indexedSetter, Func<string, T> namedGetter, Action<string, T> namedSetter)
    {
        this.indexedGetter = indexedGetter;
        this.indexedSetter = indexedSetter;
        this.namedGetter = namedGetter;
        this.namedSetter = namedSetter;
    }
}

class ReadOnlyParameterizedProperty<T>
{
    private readonly Func<int, T> getter;

    public T this[int index] => this.getter(index);

    public ReadOnlyParameterizedProperty(Func<int, T> getter)
    {
        this.getter = getter;
    }
}

class ReadOnlyNamedParameterizedProperty<T>
{
    private readonly Func<int, T> indexedGetter;
    private readonly Func<string, T> namedGetter;

    public T this[int index] => this.indexedGetter(index);
    public T this[string name] => this.namedGetter(name);

    public ReadOnlyNamedParameterizedProperty(Func<int, T> indexedGetter, Func<string, T> namedGetter)
    {
        this.indexedGetter = indexedGetter;
        this.namedGetter = namedGetter;
    }
}

So a little about my solution: I opted for Func<> & Action<> for the getters/setters because I didn't want this helper class to have to need any knowledge of underlying property it would be supporting. Instead, the class that owns the property would have public (or private) methods for get_X / set_X (or whatever naming convention you wish to use) that would handle everything - such as validation.

Now as to my use case for this: I had a class that has an internal array of a specific type. I have a default indexer property public primaryType this[int index], but it has a couple of other types that it understands and can convert to / from for primaryType. However, I can't do public otherType this[int index], and I didn't really want to do public methods called something like 'get_OtherType` & 'set_OtherType'.

These helper classes let me do something like:

public ParameterizedProperty<OtherType> OtherType { get; }

public MyClass()
{
    this.OtherType = new(get_OtherType, set_OtherType);
}

private OtherType get_OtherType(int index) 
{
    /* validate index, convert PrimaryType at index to OtherType and return. */
}

private void set_OtherType(int index, OtherType value)
{
    /* validate index, validate value, convert to PrimaryType and set to internal array. */
}

Then in other classes / UIs that use this class, where 'OtherType' is more convenient for them to work with then 'PrimaryType', I can have them doing things like myClass1.OtherType[0] = otherType;, but if they work with the primary type, then they can do myClass1[0] = primaryType - or if I just want to be consistent / explicit, I don't have a default indexer property, and I use a ParameterizedProperty for the primary type as well, IE: myClass1.PrimaryType[0] = primaryType;

Again, whether this is a good idea to go this route or not, I'm unsure.


It is possible for a class object to reasonably-efficiently have something that behaves as a named indexed property getter by having a property return a struct which simply holds a private reference to the class object and includes an indexed property getter which chains to a method in the class. Such a single-item structure can be generated at basically no cost (it can likely fit in a register, and will be loaded with a value that's in another register; the JIT may even be able to recognize that the same register can be used for both purposes), so if using such a getter makes code more readable that's a substantial argument in favor.

Unfortunately, the inability of struct members to indicate whether or not they modify the underlying structure makes it impossible to use the same approach for an indexed property setter. Even though it would be helpful it one could have have an OrderedCollection<T> with something like:

struct ByIndexAccessor {
  OrderedCollection<T> owner;
  ByIndexAccessor(OrderedCollection<T> o) { owner = o; }

  T this[int index] {
    get { return owner.handleGet(index); }
    set { owner.handleSet(index, value); }
  }
}
ByIndexAccessor ByIndex {
  get {return new ByIndexAccessor(this); }
}

and say myCollection.ByIndex[3] = newThing;, C# would reject such code because it has no way of knowing that this particular indexed set implementation can safely be used on a read-only structure.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜