通用代表C#

时间:2014-02-20 12:43:58

标签: c# generics delegates

我试图找出如何使通用委托返回通用值。 我的第一个非泛型场景看起来像这样。

    delegate int FirstDelegate(int i);
    static FirstDelegate method;

    static void Main(string[] args)
    {
        method = ReturnInt;
        int i = method(3);
    }

    static int ReturnInt(int i)
    {
        return i;
    }

这里没问题。一切正常。然而,当我把它变成通用时,事情就会失去控制。

    delegate T FirstDelegate<T>(T i);
    static FirstDelegate<T> method; <--

他已经在这里开始抱怨找不到类型或命名空间等。 任何人都有任何关于如何使这个工作的想法?

编辑:我的真正目标是我有一个可以包含许多不同缓存对象的缓存。现在我想要一个通用的方法,所以我可以通过这个方法得到所有对象。我可以让它返回对象或基类,但是我仍然必须在每个对象的任何地方使用它。

狗/猫的例子 非通用部分正在工作..通用..而不是那么多

class Program
{
    static void Main(string[] args)
    {
        //Clientside
        Cache.method = GetAnimalOnClient;

        //not working
        Cache.methodGeneric = GetAnimalOnClientGeneric;

        var cat = Cache.GetCachedObj(AnimalType.Cat);
        var dog = Cache.GetCachedObj(AnimalType.Dog);

        //Want do
        vad dog = Cache.GetCachedObj<Dog>();
    }

    private static Animal GetAnimalOnClient(AnimalType type)
    {
        if (type == AnimalType.Dog)
            return Cache._Dogs.First();
        else
            return Cache._Cats.First();
    }

    /// <summary>
    /// This is the one I want to use
    /// </summary>
    private static T GetAnimalOnClientGeneric<T>() where T: Animal
    {
        if (typeof(T) == typeof(Cat))
            return Cache._Cats.First() as T;
        return Cache._Dogs.First() as T;
    }
}

public enum AnimalType
{
    Dog,
    Cat
}

public static class Cache
{
    delegate Animal GetCacheObjectDelegate(AnimalType type);
    public static GetCacheObjectDelegate method;

    delegate Animal GetCacheObjectDelegate<T>() where T : Animal;
    public static GetCacheObjectDelegate<T> methodGeneric; //<--Complains here

    public static List<Dog> _Dogs = new List<Dog>();
    public static List<Cat> _Cats = new List<Cat>();

    public static Animal GetCachedObj(AnimalType type)
    {
        return method(type);
    }

    public static T GetCachedObj<T>() where T: Animal
    {
        return methodGeneric<T>(); //NOPE
    }
}

public class Animal
{

}

public class Dog : Animal
{

}

public class Cat : Animal
{

}

5 个答案:

答案 0 :(得分:6)

你的事情太复杂了。

public static class Cache
{
    private static List<Dog> _dogs = new List<Dog>();
    private static List<Cat> _cats = new List<Cat>();

    public static TAnimal GetCachedObj<TAnimal>() where T: Animal
    {
        if(TAnimal == typeof(Dog))
           return (TAnimal) _dogs.First();
        else if (TAnimal == typeof(Cat))
           return (TAnimal) _cats.First();
        else throw new InvalidOperationException("Invalid generic type argument");
    }
}

但是你的整个设计有一个缺陷:它打破了Liskov Substitution Principle

LSP指出,如果T(例如,Cat)是Animal的子类型,那么 Animal的任何实例都可以被替换为T没有任何令人惊讶的效果。

让我说清楚。假设您决定创建一个新动物Giraffe。现在,如果你致电GetCachedObj<Giraffe>,你将获得例外!

相反,您应该使缓存类具有通用性,并为每种动物使用缓存实例

Animal

这将永远适用于任何种类的动物。

注意:我认为public class Cache<T> where T: Animal { private static List<T> _animals = new List<T>(); public T GetCachedObj() { return _animals.First(); } } var dogsCache = new Cache<Dog>(); Dog dog = dogsCache.GetCachedObj(); var catsCache = new Cache<Cat>(); Cat cat = catsCache.GetCachedObj(); 不应该是静态的。相反,您可以使用Singleton模式在应用程序中创建一个缓存实例(每种动物类型),或使用依赖注入(使用Castle Windsor等框架)将缓存注入每个客户端。


旧答案

您可以将方法的泛型类型参数绑定到 declaration-time 中的特定类型(如提到的@Sean),也可以将封闭类型设置为泛型。

Cache

您也可以保留public class MyClass<T> { public FirstDelegate<T> Method(){...} } 未绑定(不将封闭类型设为通用),但您必须在方法名称之后声明T ,如下所示:< / p>

T

无论哪种方式,在某个时间点,public FirstDelegate<T> Method<T>(){...} 将绑定到特定类型。在这种情况下,当您创建T的实例(即T)时,MyClass将被绑定,就像使用new MyClass<int>一样。

答案 1 :(得分:4)

您需要在声明method时指定类型:

static FirstDelegate<int> method;

答案 2 :(得分:0)

如果你有一个对象的实例你想获得默认值,你可以使用它:

public static T GetDefault<T>(T par)
    {
        return default(T);
    }

例如:

System.Drawing.Point p = new Point();
System.Drawing.Point defaultPoint = GetDefault(p);

答案 3 :(得分:0)

  

我的真正目标是我有一个可以包含许多不同的缓存   缓存对象。现在我想要一个通用的方法,所以我可以   通过这一个得到所有对象。我可以让它返回对象或者   baseclass,但是我仍然需要在每个地方投射每个对象   它的用途。

在这个特定问题中不需要使用委托,因为LINQ允许从IEnumerable按类型选择对象:

public class AnimalCache

    private readonly Animals as new HashSet(of Animal)

    public function Add(Animal as Animal) as AnimalCache
        Animals.Add(Animal)
        return me
    end function

    public function GetAnimals(of AnimalType as Animal) as IEnumerable(of AnimalType)
        return Animals.OfType(of AnimalType)
    end function
end class

用法:

dim Cache = new AnimalCache().
    Add(new Cat).Add(new Dog).Add(new Cat)

dim CachedCats = Cache.GetAnimals(of Cat)
dim CachedDogs = Cache.GetAnimals(of Dog)

请注意,如果将Giraffe类添加到类层次结构中,AnimalCache仍然有效:

public class Giraffe 
    inherits Animal

end class

dim Cache = new AnimalCache().
    Add(new Cat).Add(new Dog).Add(new Giraffe)

dim CachedGiraffes = Cache.GetAnimals(of Giraffe)

答案 4 :(得分:0)

您可以在Cache类中声明一个Dictionary,使用Animal类类型作为键,并使用List&lt; Animal&gt;作为价值。

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main(string[] args)
    {
        Cache.AddCacheObj<Dog>(new Dog());
        Cache.AddCacheObj<Cat>(new Cat());

        var cat = Cache.GetCachedObj<Dog>();
        Console.WriteLine("Cat: {0}", cat);

        var dog = Cache.GetCachedObj<Cat>();
        Console.WriteLine("Dog: {0}", dog);     
    }
}

public static class Cache
{
    static Dictionary<Type, List<Animal>> dict = new Dictionary<Type, List<Animal>>();

    public static T GetCachedObj<T>() where T: Animal
    {
        List<Animal> list;
        if (dict.TryGetValue(typeof(T), out list))
        {
            return list.FirstOrDefault() as T;
        }
        return null;
    }

    public static void AddCacheObj<T>(T obj) where T: Animal
    {
        List<Animal> list;
        if (!dict.TryGetValue(typeof(T), out list))
        {
            list = new List<Animal>();
            dict[typeof(T)] = list;
        }
        list.Add(obj);
    }
}

public class Animal
{
    public override string ToString()
    {
        return "This is a " + this.GetType().ToString();
    }
}

public class Dog : Animal
{

}

public class Cat : Animal
{

}

输出:

Cat: This is a Dog
Dog: This is a Cat

您可以在此处查看演示代码: https://dotnetfiddle.net/FYkCw7