how to write a function to take any object with an

2020-05-09 23:25发布

问题:

I think I have asked this in the context of C++ (Can't find it in my question history!!) in the past and the solution was to use a template function. As C++ template resolve at compile time, it works. But for C#, it doesn't.

public Hashtable ConvertToHashtable<T>(T source) where T has an index operator
{
    Hashtable table = new Hashtable();
    table["apple"] = source["apple"];

    return table;
}

One usage at the moment is to convert the result in OleDbReader to hashtable, but I am forseeing the need for more source types soon.

回答1:

There are no generic type constraints for operators in C# - it is one of the limitations of generics in C#.



回答2:

You can use an interface:

public interface IIndexable<T> {
    T this[int index] { get; set; }
    T this[string key] { get; set; }
}

and your method will be seen as below:

public Hashtable ConvertToHashtable<T>(T source) 
    where T : IIndexable<T> {

    Hashtable table = new Hashtable();
    table["apple"] = source["apple"];
    return table;

}

A simple source is:

public class Source : IIndexable<Source> {

    public Source this[int index] {
        get {
            // TODO: Implement 
        }
        set {
            // TODO: Implement 
        }
    }

    public Source this[string key] {
        get {
            // TODO: Implement 
        }
        set {
            // TODO: Implement 
        }
    }
}

A simple consumer is:

public class Consumer{

    public void Test(){
        var source = new Source();
        var hashtable = ConvertToHashtable(source);
        // you haven't to write: var hashtable = ConvertToHashtable<Source>(source);
    }

}


回答3:

Could you add a constraint to specify that the type parameter was an IList?

public Hashtable ConvertToHashtable<T>(T source) where T : IList
{
    Hashtable table = new Hashtable();
    table["apple"] = source["apple"];

    return table;
}

The Item property this[int index] is not an operator, its a property member of the containing type. IList exposes this.



回答4:

If runtime checks are good enough, you could use reflection as one of the commentator suggested as follows:

if (typeof (T).GetProperties().Any(property => property.Name.Equals("Item")))