C# 是否可以使对象公开类型参数的接口?

C# 是否可以使对象公开类型参数的接口?,c#,oop,design-patterns,generics,C#,Oop,Design Patterns,Generics,在C#中,是否可以这样写: public class MyClass<T> : T where T : class, new() { } class Foo<T> : DynamicObject { private T _instance; public Foo(T instance) { _instance = instance; } public override bool TrySetMember

在C#中,是否可以这样写:

public class MyClass<T> : T 
    where T : class, new() 
{
}
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();
    }
}
公共类MyClass:T
其中T:class,new()
{
}
我知道上面的实现并没有编译,但我实际上想要实现的是实现某种类型的通用包装器到未知类型,这样客户机就可以像调用类型一样调用包装器,由参数
T
提供,而不是使用类似于
wrapper.Instance.SomeMember()的方法调用它

提前谢谢

这是不可能的

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

例如,假设我们有一个
引擎
类,您需要实现一个
法拉利引擎
。你有一辆
汽车

你是说
汽车
应该继承
法拉利发动机
。对我来说太可怕了

最后,您希望使用继承来执行依赖项注入之类的操作,而且,这不是正确的方法

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

更新 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>
{
}
引擎将实例化并启动,无需开发人员干预

检查
Lazy
和基本泛型约束如何生成作业;)

总之:

  • 使用
    Lazy
    仅当一些人访问
    engine
    属性时,才会实例化引擎
  • 一旦延迟加载引擎被实例化,因为
    FerrariEngine
    实现了一个调用
    Start()
    自身的无参数构造函数,它将启动引擎
我相信这个示例向您展示了如何使用C#“原样”来获得您想要的东西

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

public class MyClass<T> : T 
    where T : class, new() 
{
}
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();
    }
}
类Foo:DynamicObject
{
私人T_实例;
公共Foo(T实例)
{
_实例=实例;
}
public override bool TrySetMember(SetMemberBinder绑定器,对象值)
{
var member=typeof(T).GetProperty(binder.Name);
如果(_实例!=null&&
member.CanWrite&&
value.GetType()==member.PropertyType)
{
SetValue(_实例,value,null);
返回true;
}
返回false;
}
公共重写bool TryGetMember(GetMemberBinder绑定器,输出对象结果)
{
var member=typeof(T).GetProperty(binder.Name);
如果(_实例!=null&&
成员(可阅读)
{
结果=member.GetValue(_实例,null);
返回true;
}
结果=空;
返回false;
}
}
分类栏
{
公共int SomeProperty{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
var bar=新的bar();
动态事物=新Foo(bar);
thing.SomeProperty=42;
Console.WriteLine(thing.SomeProperty);
Console.ReadLine();
}
}

所以如果你有
类Foo{public string A;}
你想做一些类似
MyClass.A的事情吗?这正是我想要的:)我理解:)你有什么理由想这样做而不是
MyClass.Instance.A
出于好奇?monad不能满足你的需要吗@LukeHennerley:我想让这个类来管理
T
类型对象的实例,这样客户机就不需要在需要创建实例时处理这些实例。在一个非托管的世界中,你会谈论一些类似智能指针的东西。我认为C++中的行为可以通过重载<代码> -> >代码>运算符来完成,返回包含的实例。确切地说,因为<代码> CAR> <代码>和<代码>引擎< /代码>不像汽车是一个EGIN,它更像一个包含引擎的汽车,你需要知道哪一个引擎。这就是为什么我要求“类似”的东西。我不是在寻找一个基于继承的解决方案,我只是在问它是否可能,如果可能,如何实现。;)在某些情况下,类获取一个对象并以这样一种方式包装它以公开大多数底层行为是很有用的,但会改变一些细微的方面。例如,可能希望将
传递给
流读取器
,但在
流读取器
完成后,它仍然有用。目前,这样做需要使用样板代码将包装器的几乎所有成员转发到包装对象的相应成员,或者可能使用Castle Dynamic Proxy之类的东西;语言支持看起来更优雅(但还不存在)。@supercat你说得对。但是我更愿意给出没有反射发射的“官方版本”,因为我认为OP的主要问题更多的是如何在没有调用方/开发人员干预的情况下初始化关联对象。尽管这并不能真正解决我的问题,但答案回答了我的问题,描述了为什么我的问题无法以我想要的方式解决,并提出了替代方案。谢谢你:-)@Aschratt不客气!你用这种方法解决了你的问题吗?我不明白为什么在OP的问题中动态输入是有意义的。检查另一个答案:结果与使用强类型相同。区别在于您不需要实现所有包装的属性(和方法),而是使用TrySet/Get方法。当然,潜在的问题可以通过使用动态模型来解决;我只是想回答关于