繁体   English   中英

通用代表C#

[英]Generic Delegate C#

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

    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
{

}

你的事情太复杂了。

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替代原则

该LSP指出,如果T (例如, Cat )是的一个亚型Animal ,然后的任何实例Animal可以被替换T没有任何令人惊讶的效果。

让我说清楚。 假设你决定创造一种新的动物, Giraffe 现在,如果你打电话给GetCachedObj<Giraffe> ,你会得到一个例外! 该代码不会任何亚型工作Animal ,该LSP不成立!

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

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();

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

注意:我认为Cache不应该是静态的。 相反,您可以使用Singleton模式在应用程序中创建一个缓存实例(每种动物类型),或使用依赖注入(使用Castle Windsor等框架)将缓存注入每个客户端。


老答案

您可以在声明时将方法的泛型类型参数绑定到特定类型(如提到的@Sean),也可以将封闭类型设置为泛型。

public class MyClass<T>
{
    public FirstDelegate<T> Method(){...}
}

您也可以保留T unbound(不使封闭类型通用),但您必须在方法名称声明T ,如下所示:

public FirstDelegate<T> Method<T>(){...}

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

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

static FirstDelegate<int> method;

如果您有一个对象实例想要获取默认值,可以使用:

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

例如:

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

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

在这个特定问题中不需要使用委托,因为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)

您可以在Cache类中声明Dictionary,使用Animal类类型作为键,使用List <Animal>作为值。

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

暂无
暂无

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

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