简体   繁体   English

C#:我如何使用泛型创建一个实例,而它已被声明为 object

[英]C#: How do I create an instance with a generic while it has been declared as object

I am facing a problem where I want to create an instance of a SomeClass<T> where T is giving by the method, but SomeClass<T> is added to a dictionary that is declared like ConcurrentDictionary<OtherClass, SomeClass<object>> .我面临一个问题,我想创建SomeClass<T>的实例,其中T由方法给出,但SomeClass<T>被添加到声明为ConcurrentDictionary<OtherClass, SomeClass<object>>的字典中。 What I want to do does not compile because Type 'T' doesn't match expected type object我想做的事情没有编译,因为Type 'T' doesn't match expected type object

private readonly SemaphoreSlim semaphoreSlim;
private readonly ConcurrentDictionary<StatisticType, StatisticsList<object>> statisticsDictionary;

public StatisticsDictionary()
{
    semaphoreSlim = new SemaphoreSlim(1);
    statisticsDictionary = new ConcurrentDictionary<StatisticType, StatisticsList<object>>();
}

(...)

public bool TryAdd<T>(StatisticType key, DateTime dateTime, T value)
{
    if (!statisticsDictionary.ContainsKey(key))
    {
        semaphoreSlim.Wait();
        statisticsDictionary.TryAdd(key, new StatisticsList<T>());
        semaphoreSlim.Release();
    }

    if (!statisticsDictionary.TryGetValue(key, out var statistics))
        return false;

    statistics.Add(dateTime, value);
    return true;
}

The concurrentDictionary is wrapped in a class that needs to support different types of 'T' (like long, DateTime, TimeSpan and possibly other types) concurrentDictionary 包装在 class 中,需要支持不同类型的“T”(如 long、DateTime、TimeSpan 和可能的其他类型)

I've tried to just initialize SomeClass<T> as SomeClass<object> so that it matches the declaration.我试图将SomeClass<T>初始化为SomeClass<object>以便它与声明匹配。 And then on retrieval cast object to T that is given by the method.然后在检索时将object转换为方法给出的T But this leads to casting exceptions because it seems to be impossible to (explicitly) cast an object to, for example, long even when the object is in fact a long during run time.但这会导致转换异常,因为似乎不可能(明确地)将 object 转换为 long,例如,即使 object 实际上在运行期间很长。

public bool TryGetFrom<T>(StatisticType key, DateTime from, out IEnumerable<(DateTime, T)> value)
{
    if (statisticsDictionary.TryGetValue(key, out var statistics))
    {
        var list = statistics.TryGetFrom(from);
        value = (IEnumerable<(DateTime, T)>) list;

        return value != null;
    }

    value = null;
    return false;
}

Is it even possible what I try to accomplish?甚至有可能我试图完成的事情吗?


Edit Source code of StatisticsList as requested in the comments根据评论中的要求编辑StatisticsList 的源代码

public class StatisticsList<T>
{
    private readonly SemaphoreSlim semaphoreSlim;
    private readonly SortedList<DateTime, (DateTime, T)> sortedList;
    public DateTime StartedAt { get; }
    public int Count => sortedList.Count;

    public StatisticsList()
    {
        try
        {
            semaphoreSlim.Wait();
            sortedList.Add(key, (key, value));
        }
        finally
        {
            semaphoreSlim.Release();
        }
    }

    public void Add(DateTime key, T value)
    {
        semaphoreSlim.Wait();
        sortedList.Add(key, (key, value));
        semaphoreSlim.Release();
    }

    public bool TryGetFrom(DateTime from, out IEnumerable<(DateTime, T)> value)
    {
        try
        {
            semaphoreSlim.Wait();
            value = sortedList.Where(s => s.Key > from).Select(s => s.Value).ToList();
            return true;
        }
        catch (ArgumentNullException) { }
        finally
        {
            semaphoreSlim.Release();
        }

        value = null;
        return false;
    }

    public bool TryGetLast(out (DateTime, T) value)
    {
        try
        {
            semaphoreSlim.Wait();
            var dateTime = sortedList.Max(s => s.Key);
            return sortedList.TryGetValue(dateTime, out value);
        }
        catch (ArgumentNullException)
        {
            value = (default, default);
        }
        finally
        {
            semaphoreSlim.Release();
        }

        return false;
    }

    public IEnumerable<(DateTime, T)> ToList()
    {
        try
        {
            semaphoreSlim.Wait();
            return sortedList.Values.ToList();
        }
        finally
        {
            semaphoreSlim.Release();
        }
    }
}

Generics are effective when you know the type during design-time.当您在设计时知道类型时,Generics 是有效的。 In your case, your collection can store items of any different types.在您的情况下,您的收藏可以存储任何不同类型的项目。

You can utilize a pretty popular trick of declaring non-generic and inherited generic version of a collection item.您可以利用一个非常流行的技巧来声明集合项的非泛型和继承的泛型版本。 As a side effect, you can get rid of a not-very-readable value tuple:)作为副作用,您可以摆脱不太可读的值元组:)

Declare item class like this:像这样声明项目 class :

public abstract class StatisticsListItem
{
    public DateTime Time { get; protected set; }
}

public class StatisticsListItem<T> : StatisticsListItem 
{
    public StatisticsListItem(DateTime time, T value)
    {
        Time = time;
        Value = value;
    }

    public T Value { get; }
}

And then you can store them as StatisticsListItem and perform operations depending on their specific sub-type.然后您可以将它们存储为StatisticsListItem并根据它们的特定子类型执行操作。 It is also type-safe, because you cannot access the value of a generic list item, like in case if you declare it as non-generic StatisticsListItem with object Value { get; }它也是类型安全的,因为您无法访问通用列表项的值,例如如果您使用object Value { get; }将其声明为非通用StatisticsListItem object Value { get; } property. object Value { get; }财产。

The simplest usage scenario can look like this:最简单的使用场景可以是这样的:

public class StatisticsList
{
    public List<StatisticsListItem> Values { get; set; } = new List<StatisticsListItem>();

    public void TryAdd<T>(DateTime dateTime, T value)
    {
        // Adding an item of generic type to non-generic list:
        Values.Add(new StatisticsListItem<T>(dateTime, value));
    }

    public IEnumerable<StatisticsListItem<T>> TryGetFrom<T>(DateTime dateTime) 
    {  
        // Dynamically filtering only items of specific generic type
        return Values
            .OfType<StatisticsListItem<T>>() // computationally ineffective, subject to improvement ;)
            .Where(t => t.Time >= dateTime); // same, just an example
    }
}

It is just an example.这只是一个例子。 You still need to implement it in a way it supports keys, fits into your dictionary and makes filtering of items by type much more effective.您仍然需要以支持键、适合您的字典并使按类型过滤项目更有效的方式来实现它。 Good luck!祝你好运!

Some minor comments: you still might have some problems with handling multi-threading, but this is out of the scope of this question:)一些小评论:您在处理多线程方面可能仍然存在一些问题,但这不在此问题的 scope 范围内:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM