声明属性为函数委托的正确方法是什么

时间:2013-02-02 17:57:06

标签: c#

我的程序中有一个名为SortableObservableCollection<T>的类,它继承自ObservableCollection<T>。它有一个名为Sort的函数:

public void Sort<TKey>( Func<T, TKey> keySelector, int skip = 0 ) 
{
   // . . .
}

我想声明一个名为Key1的{​​{1}}类型的属性。我试过了:

Func<T, TKey>

但是我在左大括号上遇到语法错误。该错误表明编译器期望左括号。我试过把它变成一个字段声明:

public Func<T, TKey> Key1<T, TKey> { get; set; }

但是编译器在分号上给了我相同的信息。

声明此属性的正确语法是什么?

5 个答案:

答案 0 :(得分:3)

首先,您需要扩展类定义以包含TKey的通用参数,而不是仅仅使用Sort()方法级别:

public class SortableObservableCollection<T, TKey>
{
}

之后,您将不需要第二组通用参数:

public Func<T, TKey> Key1 { get; set; }

您还可以从Sort()方法中删除通用参数。

答案 1 :(得分:3)

您正在尝试创建一个通用属性,但属性不能是通用的。你必须以某种方式解决这个问题。我可以想到几个选择:

  1. 将委托声明为object - 返回:

    public Func<T, object> Key1 { get; set; }
    
  2. 将属性设置为方法(或两个方法,如果您还需要getter)。这样做的问题是你需要将委托存储在非泛型字段中,之后很难处理它:

    private Delegate key1;
    
    public void SetKey1<TKey>(Func<T, TKey> key1)
    {
        this.key1 = key1;
    }
    
  3. 如果排序键的类型不会更改,请将其设为类的类型参数:

    public class SortableObservableCollection<T, TKey>
    {
        public Func<T, TKey> Key1 { get; set; }
    
        …
    }
    

答案 2 :(得分:1)

这里有2个选项。 首先,您可以将TKey作为通用参数添加到类中。

public class SortableObservableCollection<T, TKey> : ObservableCollection<T>
{
    public void Sort(Func<T, TKey> keySelector, int skip = 0)
    {
        //...
    }
    public Func<T, TKey> Key1 { get; set; }
}

现在,如果您不能或不想在该类中添加另一个通用参数,那么您的第二个选项是避免一起使用Key1的属性。

public class Sort2<T> : ObservableCollection<T>
{
    Type keyType;
    object key1;

    public void Sort<TKey>(Func<T, TKey> selector, int skip = 0)
    {
        //...
    }

    public void SetKey<TKey>(TKey val)
    {
        keyType = typeof(TKey);
        key1 = val;
    }
    public TKey GetKey<TKey>()
    {
        return (TKey)key1;
    }

    public Type GetKeyType()
    {
        return keyType;
    }

}

答案 3 :(得分:0)

试试这个:

public class SortableObservableCollection<T, TKey>:ObservableCollection<T>
{
    public Func<T,TKey> Key1 {get; set;}
}

答案 4 :(得分:0)

虽然每个人的答案都有效,但他们并不是我想要解决的问题。最初,我有一个名为Sort:

的类的方法
public void Sort<TKey>( Func<T, TKey> keySelector, . . . ) {
    // . . .
}

这很好用,但后来我在UI中发现了一个与多次调用Sort方法有关的错误。排序本身有效,这不是问题。这个错误令人费解,很难解释,我宁愿不去讨论它。但最简单的解决方案是确保集合只在正确的密钥上排序一次。问题是密钥的不同取决于集合绑定的特定下拉。所以我需要一种方法来在集合中封装排序条件,这样它就可以在第一次也是唯一一次进行正确的排序。

由于我已经使用了上面提到的Sort方法,我认为最简单的方法是将keySelector参数放入类的属性中。事实证明,语言不会让你这样做,现在我知道并理解为什么。

我最终要做的就是将Func属性替换为对实现IComparer<T>的对象的引用。我声明这个属性没有问题,并且很容易为集合声明中作为T参数传递的每个类型声明一个实现它的类。我只是在分配了集合对象之后初始化了属性,并重新编写了Sort方法,所以看起来像这样:

public void Sort() {
    if ( Comparer != null ) {
        InternalSort( Items.Skip( RowsToSkip ).OrderBy( item => item, Comparer ) );
    } else { 
        InternalSort( Items.Skip( RowsToSkip ).OrderBy( item => item ) );
    }
}

RowsToSkip是类的int属性,用于指定要跳过集合开头的行数。这让我可以在列表的开头添加“选择一个选项”这样的条目,而不是让它移动它。