C# 如何在C中进行模板专门化#

C# 如何在C中进行模板专门化#,c#,partial-specialization,C#,Partial Specialization,你会怎样做C#专业 我会提出一个问题。你有一个模板类型,你不知道它是什么。但是您知道它是否是从XYZ派生的,您想调用.alternativeFunc()。一个很好的方法是调用一个专门化的函数或类,并让normalCall返回.normalFunc(),同时让任何派生类型的XYZ上的其他专门化调用.alternativeFunc()。在C++中如何做到这一点?< p>假设你在讨论模板特化,因为它可以用C++模板来完成。这是因为C#泛型在编译过程中不会被处理,而更像是运行时的一项功能 但是,您可以使

你会怎样做C#专业


我会提出一个问题。你有一个模板类型,你不知道它是什么。但是您知道它是否是从
XYZ
派生的,您想调用
.alternativeFunc()
。一个很好的方法是调用一个专门化的函数或类,并让
normalCall
返回
.normalFunc()
,同时让任何派生类型的
XYZ
上的其他专门化调用
.alternativeFunc()
。在C++中如何做到这一点?

< p>假设你在讨论模板特化,因为它可以用C++模板来完成。这是因为C#泛型在编译过程中不会被处理,而更像是运行时的一项功能

但是,您可以使用C#3.0扩展方法实现类似的效果。下面的示例演示了如何仅为
MyClass
type添加扩展方法,这与模板专门化类似。但是请注意,您不能使用它来隐藏该方法的默认实现,因为C#编译器总是更喜欢标准方法而不是扩展方法:

class MyClass<T> {
  public int Foo { get { return 10; } }
}
static class MyClassSpecialization {
  public static int Bar(this MyClass<int> cls) {
    return cls.Foo + 20;
  }
}

如果您只想测试某个类型是否从XYZ派生,则可以使用:

theunknownobject.GetType().IsAssignableFrom(typeof(XYZ));
如果是这样,您可以将“theunknownobject”强制转换为XYZ并像下面这样调用alternativeFunc():

XYZ xyzObject = (XYZ)theunknownobject; 
xyzObject.alternativeFunc();
希望这有帮助

在C#中,最接近专门化的是使用更具体的重载;然而,这是脆弱的,并不能涵盖所有可能的用途。例如:

void Foo<T>(T value) {Console.WriteLine("General method");}
void Foo(Bar value) {Console.WriteLine("Specialized method");}
然而

void Test<TSomething>(TSomething value) {
    Foo(value);
}

这里,
Bar.Foo
将始终解析为正确的重写。

通过添加一个中间类和一个字典,专门化是可能的

为了专门化T,我们创建了一个通用接口,有一个名为(例如)Apply的方法。对于实现接口的特定类,定义该类的方法Apply specific。这个中间类称为traits类

该traits类可以在泛型方法的调用中指定为参数,然后(当然)总是采用正确的实现

traits类也可以存储在全局
IDictionary
中,而不是手动指定。然后你可以查一下,瞧,你有真正的专长

如果方便,您可以在扩展方法中公开它

class MyClass<T>
{
    public string Foo() { return "MyClass"; }
}

interface BaseTraits<T>
{
    string Apply(T cls);
}

class IntTraits : BaseTraits<MyClass<int>>
{
    public string Apply(MyClass<int> cls)
    {
        return cls.Foo() + " i";
    }
}

class DoubleTraits : BaseTraits<MyClass<double>>
{
    public string Apply(MyClass<double> cls)
    {
        return cls.Foo() + " d";
    }
}

// Somewhere in a (static) class:
public static IDictionary<Type, object> register;
register = new Dictionary<Type, object>();
register[typeof(MyClass<int>)] = new IntTraits();
register[typeof(MyClass<double>)] = new DoubleTraits();

public static string Bar<T>(this T obj)
{
    BaseTraits<T> traits = register[typeof(T)] as BaseTraits<T>;
    return traits.Apply(obj);
}

var cls1 = new MyClass<int>();
var cls2 = new MyClass<double>();

string id = cls1.Bar();
string dd = cls2.Bar();
class-MyClass
{
公共字符串Foo(){返回“MyClass”;}
}
界面基本特征
{
字符串应用(T cls);
}
类IntTraits:BaseTraits
{
公共字符串应用(MyClass cls)
{
返回cls.Foo()+“i”;
}
}
类双重特征:基本特征
{
公共字符串应用(MyClass cls)
{
返回cls.Foo()+“d”;
}
}
//在(静态)类中的某个位置:
公共静态词典登记册;
寄存器=新字典();
寄存器[typeof(MyClass)]=新的IntTraits();
寄存器[typeof(MyClass)]=新的DoubleTraits();
公共静态字符串栏(此T obj)
{
基本性状=作为基本性状的登记[类型(T)];
返回特征。应用(obj);
}
var cls1=新的MyClass();
var cls2=新的MyClass();
字符串id=cls1.Bar();
字符串dd=cls2.Bar();

请参阅我最近的博客和后续文章,了解详细的描述和示例。

一些建议的答案使用了运行时类型信息:天生比编译时绑定的方法调用慢

编译器不强制执行专门化,也不强制在C++中执行。


我建议在PASTHARP中找到一种方法,在通常编译器完成后,可以实现类似C++的效果。

< P>我也在寻找一个模式来模拟模板特化。有些方法在某些情况下可能有效。但是这个案子呢

static void Add<T>(T value1, T value2)
{
    //add the 2 numeric values
}
现在,我们可以在不必事先知道类型的情况下编写:

static T Add<T>(T value1, T value2)
{
    return Math<T>.P.Add(value1, value2);
}

private static void Main(string[] args)
{
    var result1 = Add(1, 2);
    var result2 = Add(1.5, 2.5);

    return;
}
静态T添加(T值1,T值2)
{
返回Math.P.Add(值1、值2);
}
私有静态void Main(字符串[]args)
{
var result1=相加(1,2);
var result2=相加(1.5,2.5);
返回;
}

如果不仅应该为实现的类型调用专门化,而且还应该为派生类型调用专门化,那么可以为接口使用
In
参数。但是,在这种情况下,方法的返回类型不能再是泛型类型
T

我认为有一种方法可以通过.NET 4+使用动态分辨率实现它:

static class Converter<T>
{
    public static string Convert(T data)
    {
        return Convert((dynamic)data);
    }

    private static string Convert(Int16 data) => $"Int16 {data}";
    private static string Convert(UInt16 data) => $"UInt16 {data}";
    private static string Convert(Int32 data) => $"Int32 {data}";
    private static string Convert(UInt32 data) => $"UInt32 {data}";
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Converter<Int16>.Convert(-1));
        Console.WriteLine(Converter<UInt16>.Convert(1));
        Console.WriteLine(Converter<Int32>.Convert(-1));
        Console.WriteLine(Converter<UInt32>.Convert(1));
    }
}

这表明不同的类型需要不同的实现。

我对C#知道的不多,但是投票反对你的人应该说为什么。我不知道你的答案出了什么问题,也不知道是否有什么问题。对我来说,这似乎足够有效。虽然有点过于冗长,但不是我,而是因为答案与问题完全无关。查找
“c++模板专门化”
这并不总是有效的。例如,您无法看到t是否为bool,然后将其转换为bool.Foo属性vs Bar方法。。。看起来并不是典型的专业化…不,这不是典型的专业化,但这是你能做的唯一简单的事情。。。(AFAIK)在不使用扩展方法的情况下,这看起来也可以很好地工作——只需采用泛型类型的
static
方法。也就是说,@MarcGravel answer中指出的问题似乎可以通过基于类似于
MyClass
/
MyClass
的参数来“模板化”方法来解决,而不是将方法模板化为特定的“数据”类型(
T
/
int
)。另外的限制是,它不适用于间接的泛型调用,例如,从一个方法中
void callpropertebar(){(new MyClass()).Bar();}
。这是工厂模式,它是解决generics@Yaur我看起来像教科书上的装饰图案。这真是太棒了,谢谢。它允许我创建一个通用接口,用于调用一组预先存在的方法,每个方法都是为特定的ty编写的
class MyClass<T>
{
    public string Foo() { return "MyClass"; }
}

interface BaseTraits<T>
{
    string Apply(T cls);
}

class IntTraits : BaseTraits<MyClass<int>>
{
    public string Apply(MyClass<int> cls)
    {
        return cls.Foo() + " i";
    }
}

class DoubleTraits : BaseTraits<MyClass<double>>
{
    public string Apply(MyClass<double> cls)
    {
        return cls.Foo() + " d";
    }
}

// Somewhere in a (static) class:
public static IDictionary<Type, object> register;
register = new Dictionary<Type, object>();
register[typeof(MyClass<int>)] = new IntTraits();
register[typeof(MyClass<double>)] = new DoubleTraits();

public static string Bar<T>(this T obj)
{
    BaseTraits<T> traits = register[typeof(T)] as BaseTraits<T>;
    return traits.Apply(obj);
}

var cls1 = new MyClass<int>();
var cls2 = new MyClass<double>();

string id = cls1.Bar();
string dd = cls2.Bar();
static void Add<T>(T value1, T value2)
{
    //add the 2 numeric values
}
public interface IMath<T>
{
    T Add(T value1, T value2);
}

public class Math<T> : IMath<T>
{
    public static readonly IMath<T> P = Math.P as IMath<T> ?? new Math<T>();

    //default implementation
    T IMath<T>.Add(T value1, T value2)
    {
        throw new NotSupportedException();    
    }
}

class Math : IMath<int>, IMath<double>
{
    public static Math P = new Math();

    //specialized for int
    int IMath<int>.Add(int value1, int value2)
    {
        return value1 + value2;
    }

    //specialized for double
    double IMath<double>.Add(double value1, double value2)
    {
        return value1 + value2;
    }
}
static T Add<T>(T value1, T value2)
{
    return Math<T>.P.Add(value1, value2);
}

private static void Main(string[] args)
{
    var result1 = Add(1, 2);
    var result2 = Add(1.5, 2.5);

    return;
}
static class Converter<T>
{
    public static string Convert(T data)
    {
        return Convert((dynamic)data);
    }

    private static string Convert(Int16 data) => $"Int16 {data}";
    private static string Convert(UInt16 data) => $"UInt16 {data}";
    private static string Convert(Int32 data) => $"Int32 {data}";
    private static string Convert(UInt32 data) => $"UInt32 {data}";
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Converter<Int16>.Convert(-1));
        Console.WriteLine(Converter<UInt16>.Convert(1));
        Console.WriteLine(Converter<Int32>.Convert(-1));
        Console.WriteLine(Converter<UInt32>.Convert(1));
    }
}
Int16 -1
UInt16 1
Int32 -1
UInt32 1