c#中定义较少的泛型?

时间:2009-12-03 15:44:27

标签: c# generics collections

有没有办法在不提供基础类型的情况下使用泛型类的集合? 我们来解释一下:

以下是我想要的内容:

class TimeSerie<TValue> {
enter code here
}

List<TimeSerie<?>> blah;

这是我到目前为止所要做的:

class TimeSerie {}
class TypedTimeSerie<TValue> : TimeSerie {}

List<TimeSerie> blah;

那么,有什么办法可以使用漂亮的第一个解决方案吗? (虽然我想在尝试施放时会引发问题,例如循环...)

5 个答案:

答案 0 :(得分:8)

您也可以使使用代码通用...但在某些时候您必须指定类型参数。如果不知道类型参数,您将无法创建泛型类型的实例。如果必须,您可以在执行时使用反射提供该信息,但必须以某种方式

答案 1 :(得分:1)

我根据您的问题没有看到为什么您无法从ICollection<T>List<T>派生自定义集合(或者可能派生自ICollection并将调用委托给List<T>类型的字段内部存储?

(完全可能我只是没有得到它,但你可以提供更多的示例代码吗?)

答案 2 :(得分:1)

为什么不呢?

List<TimeSerie<Object>> blah;

然后指定对象后。还要相应地定义基类。

答案 3 :(得分:1)

请注意,对于使用c#的匿名类型,可能会出现一些'mumbling',这要归功于两件事:

  1. 类型推断
  2. 统一相同的匿名类型
  3. 如果你很乐意依赖这两件事情来保持固定(对此没有任何保证,特别是与2相关),那么以下内容可能会有用。

    public static class Mumble 
    {
        public static HashSet<T> HashSet<T>(T prototype)
        {
            return new HashSet<T>();
        }
    
        public static List<T> List<T>(T prototype)
        {
            return new List<T>();
        } 
    }
    

    您可以像这样使用它:

    var set = MumbleSet(new { Foo="", Bar="", Baz=0 });
    var list = MumbleList(new { Foo="", Bar="", Baz=0 });
    set.Add(new { Foo="x", Bar="y", Baz=1 });
    set.Add(new { Foo="a", Bar="b", Baz=1 });
    list.Add(new { Foo="a", Bar="b", Baz=1 });
    var intersection = list.Intersect(set);
    var concat = list.Concat(set); 
    

    这适用于您希望填充到某个其他集合中以便在方法中的其他位置使用的匿名类型的情况。一个常见的用途是从数据库查询读取到一个集合中,以便在循环中检查是否存在,其中表达为一系列linq查询太麻烦或太昂贵。

    对于您的激励示例,您必须添加以下内容:

    class TimeSerie<TValue> 
    {   
        // or some other constructor equivalent 
        public TimeSerie(TValue value) { /* assign the value */ }
    }
    
    static class TimeSerieMumble
    {
        public static TimeSerie<TValue> New<TValue>(TValue value)
        {
            return new TimeSerie<TValue>(value);
        }
    }
    

    然后你就可以使用这样的代码:

    var tsList = Mumble.List(TimeSerieMumble.New(new { Name="", Value=0 }));
    foreach (var x in from c select new { c.Name, c.Value })
    {
        tsList.Add(TimeSerieMumble.New(new { x.Name, x.Value }));
    }
    

    在c#3.5中泄漏'泄漏'到公共API中是不可行的,除非该类型通过一系列类型推断的泛型方法以与上述示例相同的方式进行混淆。鉴于调用代码所需的扭曲,我从未见过这样的事情是有用的。我认为它也不会提高可读性。根据经验,在名称/价值示例中使用超过两个级别的笨拙可能会导致严重的并发症。

答案 4 :(得分:0)

正如其他人所说,在C#中做到这一点并不容易。 但是,如果它真的很重要,可以使用一些额外的类型忠实地编码这个模式,虽然它有点难看:

interface ITimeSeriesUser<X> {
    X Use<T>(TimeSeries<T> series);
}

interface ITimeSeriesUser {
    void Use<T>(TimeSeries<T> series);
}

interface ITimeSeries {
    X Apply<X>(ITimeSeriesUser<X> user);
    void Apply(ITimeSeriesUser user);
}

class TimeSeries<T> : ITimeSeries {
    X Apply<X>(ITimeSeriesUser<X> user) { return user.Use(this); }
    void Apply(ITimeSeriesUser user) { return user.Use(this); }

    /* Your existing code goes here */
}

现在,您可以创建一个List<ITimeSeries>实例,其中包含TimeSeries<T>  值,无论其类型参数如何,您都可以使用ITimeSeriesUser 实现操纵它们。显然这需要相当多的样板,  但如果你需要一种忠实的方式来表达TimeSeries<?>的概念,那么这可能是你最好的选择。