2013-02-02 95 views
0

我的程序中有一个类SortableObservableCollection<T>,它继承自ObservableCollection<T>。它有一个叫做Sort功能:声明属性是函数委托的正确方法是什么

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

我要声明一个名为Func<T, TKey>类型的Key1财产。我已经尝试过:

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

但是我得到左花括号的语法错误。该错误表示编译器期待左括号。我试过把它作为一个字段声明:

public Func<T, TKey> Key1<T, TKey>; 

但是然后编译器给我在分号上相同的消息。

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

+2

属性不能像通用方法一样泛型,请参阅[为什么C#不允许泛型属性?](http://stackoverflow.com/questions/8620883/)。如果该属性位于通用类的类(或结构或接口)内,则该属性的类型当然可能取决于包含类的类型参数,但该属性不能像通用方法那样引入新的类型参数。 –

+0

@JeppeStigNielsen:谢谢。虽然我没有阅读所有内容,但是你提供的链接解释了为什么我不能做我想做的事情。 –

回答

0

虽然每个人的答案会的工作,他们不正是我一直想把这个问题。我本来类的方法称为Sort:

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

这个工作很好,但后来我发现是有关调用排序方法不止一次在我的UI中的错误。排序本身起作用,那不是问题。这个错误很复杂,很难解释,我宁愿不去理解它。但最简单的解决方案是确保集合只在正确的密钥上排序一次。关键在于键的不同取决于集合绑定的特定下拉菜单。所以我需要一种方法来封装收集中的排序标准,以便它能够在唯一的时间进行正确的排序。

因为我已经有了上述的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财产被跳过。这使我可以在列表的开始处添加一个条目,如“选择一个选项”,但不能将其移动。

3

首先,你需要扩大你的类定义为包括TKey泛型参数,而不是仅仅让它在Sort()方法级别:

public class SortableObservableCollection<T, TKey> 
{ 
} 

之后,你将不再需要第二一套通用的参数:

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

您也可以从Sort()方法去除泛型参数。

+0

当我尝试这样做时,我得到“无法找到类型或名称空间名称'TKey'(您是否缺少使用指令或程序集引用?”) –

+0

@Tony - 该声明假定TKey是通用参数类。如果不是,您需要定义一些具体类型而不是泛型参数。 –

0

试试这个:

public class SortableObservableCollection<T, TKey>:ObservableCollection<T> 
{ 
    public Func<T,TKey> Key1 {get; set;} 
} 
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

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

  1. 声明委托作为object -returning:

    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; } 
    
        … 
    } 
    
相关问题