8

在 C# 中,是否可以编写如下内容:

public class MyClass<T> : T 
    where T : class, new() 
{
}

我知道上面的实现无法编译,但我实际上想要实现的是对未知类型实现某种通用包装器,以便客户端可以像调用类型一样调用包装器,由参数提供T,而不是使用类似的东西来调用它wrapper.Instance.SomeMember()

提前致谢!

4

2 回答 2

5

这是不可能的。

在我看来,我认为不应该使用继承来实现包装器。

例如,假设我们有一个Engine类,您需要实现一个FerrariEngine. 你有一Car堂课。

你是说Car应该继承FerrariEngine。这对我来说看起来很糟糕!

归根结底,您希望使用继承执行依赖注入之类的操作,而且这又不是正确的方法。

我的建议是不要试图让你的生活更轻松:根据理性点决定架构。

更新

OP在一些评论中说:

我想让这个类来管理类型为 T 的对象的实例,这样客户端就不需要关心何时需要创建实例。

你不需要做奇怪的事情来得到你想要的:

public interface IEngine 
{
     void Start();
}

public sealed class FerrariEngine : IEngine
{
     public FerrariEngine()
     {
          Start();
     }

     public void Start()
     {
     }
}

public abstract class Car<TEngine> where TEngine: IEngine, new()
{
    public Car()
    {
        _engine = new Lazy<TEngine>(() => new TEngine());
    }

    private readonly Lazy<TEngine> _engine;

    public TEngine Engine
    {
        get { return _engine.Value; }
    }
}

public class FerrariCar : Car<FerrariEngine>
{
}

最后,如果我们创建一个实例FerrariCar

Car<FerrariEngine> myFerrari = new FerrariCar();

引擎将被实例化并启动,无需开发人员干预!

检查Lazy<T>基本的通用约束是如何完成这项工作的;)

总之:

  • 只有当某些人访问该属性Lazy<T>时,才会实例化使用引擎。Engine
  • 一旦延迟加载引擎被实例化,由于FerrariEngine实现了一个调用Start()自身的无参数构造函数,它将启动引擎。

我相信这个示例向您展示了如何获得所需的内容并“按原样”使用 C#!

于 2013-01-25T11:11:15.023 回答
1

您可以查看DynamicObject并执行以下操作:

class Foo<T> : DynamicObject
{
    private T _instance;
    public Foo(T instance)
    {
        _instance = instance;
    }
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        var member = typeof(T).GetProperty(binder.Name);
        if (_instance != null &&
            member.CanWrite &&
            value.GetType() == member.PropertyType)
        {
            member.SetValue(_instance, value, null);
            return true;
        }
        return false;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var member = typeof(T).GetProperty(binder.Name);
        if (_instance != null &&
            member.CanRead)
        {
            result = member.GetValue(_instance, null);
            return true;
        }
        result = null;
        return false;
    }
}

class Bar
{
    public int SomeProperty { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var bar = new Bar();
        dynamic thing = new Foo<Bar>(bar);
        thing.SomeProperty = 42;
        Console.WriteLine(thing.SomeProperty);
        Console.ReadLine();
    }
}
于 2013-01-25T11:55:18.300 回答